SIP-140: Allow Exchange Into Origin Address


Simple Summary

Add an additional exchange function to Synthetix to support transactions initiated by a user but performed through another address.


Modify the Synthetix contract with an additional exchange function that uses tx.origin as the destinationAddress, allowing the exchange (and fee reclamation) recipient to be different from the msg.sender.

Motivation would like to use Synthetix exchanges in their router as a final step in a route. This would open up routes like WBTC > sBTC > sUSD for instance. Right now, this cannot be done as 1inch creates a contract to perform all legs of the route and at the end, they transfer the funds to the user. As this contract is created at the time of the trade, it doesn't work with the exchangeOnBehalf delegation features already inside Synthetix.

Now, the reason Synthetix exchanges do not currently support a custom destinationAddress is that this could be an attack vector. Imagine a scenario where a user frontruns a synth into sUSD and uses their Binance deposit address as the destination. In this instance, Binance would lose out and the user would make risk-free profit.

As such, this proposal insists that the only destinationAddress that is allowed is tx.origin. This works for most cases, but would fail for any contracts that use 1inch to transact - such as multisigs like Gnosis safe. This is considered an acceptable compromise for now.

Note: Fee reclamation would exist, but since it's the final step in the route, it's up to the user to later call Exchanger.settle or Synth.transferAndSettle()



An additional exchangeWithTracking function to be added to Synthetix which uses tx.origin as the destinationAddress of an exchange.


The Exchanger contract already supports the destinationAddress parameter on it's restricted exchange() function, so adding another function to Synthetix which invokes Exchanger with destinationAddress as tx.origin is fairly trivial.

The exchangeWithTracking function will be used as a base, as this SIP's functionality is primarily for aggregators like 1inch which would like it to support the volume program via the trackingCode parameter.

Technical Specification

interface ISynthetix {
    function exchangeWithTrackingForInitiator(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        address originator,
        bytes32 trackingCode
    ) external returns (uint amountReceived);

Test Cases

  • Given Amy has written a contract which includes a public function that calls Synthetix.exchangeWithTrackingForInitiator(), When she invokes this public function to trade sUSD for sETH, Then her EOA which invoked the transaction ends up with the sETH, and the fee reclamation settlement applies to that same EOA.
  • Given Brian invokes a 1inch contract to trade 1 WBTC for sUSD which steps through Synthetix via Synthetix.exchangeWithTrackingForInitiator(), Then Brian ends up with the total amount of sUSD from the exchange, and the fee reclamation settlement applies to Brian's account.

⚠️⚠️⚠️ Note: This new function is designed for the sole use-case of a user who initiates the contract ending up with the proceeds of the exchange. This may have unintended consequences for any contracts that use 1inch to transact - including multisigs like Gnosis safe. This is considered an acceptable limitation for now.

Configurable Values (Via SCCP)


Copyright and related rights waived via CC0.