Skip to content

Trading: Exchanging Synths

Synths can be directly exchanged for one another with zero slippage. To view a full list of all the synthetic assets available for trading on Synthetix, visit our tokens section.

Exchanging API

Contract

Destination contract (address): ProxyERC20

Target contract (ABI): Synthetix

Note: Synthetix uses a proxy system. The ABI of the underlying Synthetix ProxyERC20 contract you need is Synthetix. Learn more about how proxies work by visiting the overview page

Methods

Events Emitted

On a successful transaction, the following events occur:

If any fees are owing or owed, these events will come first. See trade settlement for information.

Following any reclaims or rebates, the following events then occur:

name emitted on address from address to uint value
Transfer Proxy<src> msg.sender (or user) 0x0 fromAmount
name emitted on address account uint value
Burned Proxy<src> msg.sender (or user) fromAmount
name emitted on address from address to uint value
Transfer Proxy<dest> 0x0 msg.sender (or user) toAmount - fee
name emitted on address account uint value
Issued Proxy<dest> msg.sender (or user) toAmount - fee
name emitted on address from address to uint value
Transfer ProxysUSD 0x0 FEE_ADDRESS fee
name emitted on address account uint value
Issued ProxysUSD FEE_ADDRESS fee
name emitted on uint cachedDebt
DebtCacheUpdated DebtCache New cachedDebt in the system (see SIP-91)
name emitted on address account bytes32 src uint fromAmount bytes32 dest uint toAmount address toAddress
SynthExchange ProxySynthetix msg.sender
(or user)
src fromAmount dest toAmount - fee msg.sender
(or user)
name emitted on address account bytes32 src uint amount bytes32 dest uint amountReceived uint exchangeFeeRate uint roundIdForSrc uint roundIdForDest
ExchangeEntryAppended Exchanger msg.sender
(or user)
src fromAmount dest toAmount - fee the exchangeFeeRate paid the roundId for rate of src synth the roundId for rate of dest synth

Examples from Mainnet

  • ProxySynthetix.exchange(sETH, 100e18, iETH)
  • ProxySynthetix.exchange(iETH, 0.22e18, sUSD) (with a Reclaim)
  • ProxySynthetix.exchange(sETH, 5e18, sUSD) (with a Rebate)

Code Snippets

Exchanging (Trading)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const { SynthetixJs } = require('synthetix-js');
const privateKey = '0x' + '1'.repeat(64); // don't actually put a private key in code obviously

// parameters: default provider, default networkId, private key as a string
const networkId = 11155111; // sepolia, (use 1 for mainnet)
const signer = new SynthetixJs.signers.PrivateKey(null, networkId, privateKey);
const snxjs = new SynthetixJs({ signer, networkId });

const { toUtf8Bytes32, parseEther } = snxjs.utils;

(async () => {
  try {
    // send transaction
    const txn = await snxjs.Synthetix.exchange(toUtf8Bytes32('sUSD'), parseEther('0.001'), toUtf8Bytes32('iETH'));

    console.log('hash is mining', txn.hash);

    // wait for mining
    await txn.wait();

    // fetch logs of transaction
    const { logs } = await signer.provider.getTransactionReceipt(txn.hash);

    // show them
    console.log(JSON.stringify(logs, null, '\t'));
  } catch (err) {
    console.log('Error', err);
  }
})();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const synthetix = require('synthetix'); // nodejs
const ethers = require('ethers'); // nodejs
// or using ES modules:
// import synthetix from 'synthetix';
// import ethers from 'ethers';

const network = 'sepolia';
const provider = ethers.getDefaultProvider(network === 'mainnet' ? 'homestead' : network);

const { address } = synthetix.getTarget({ network, contract: 'ProxyERC20' });
const { abi } = synthetix.getSource({ network, contract: 'Synthetix' });

const privateKey = '0x' + '1'.repeat(64); // don't actually put a private key in code obviously
const signer = new ethers.Wallet(privateKey).connect(provider);

// see https://docs.ethers.io/ethers.js/html/api-contract.html#connecting-to-existing-contracts
const Synthetix = new ethers.Contract(address, abi, signer);
const { toBytes32 } = synthetix;

(async () => {
  try {
    // send transaction
    const txn = await Synthetix.exchange(toBytes32('sUSD'), ethers.utils.parseEther('0.001'), toBytes32('iETH'));

    // wait for mining
    await txn.wait();
    // fetch logs of transaction
    const { logs } = await provider.getTransactionReceipt(txn.hash);
    // display
    console.log(JSON.stringify(logs, null, '\t'));
  } catch (err) {
    console.log('Error', err);
  }
})();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
pragma solidity 0.5.16;

import "synthetix/contracts/interfaces/IAddressResolver.sol";
import "synthetix/contracts/interfaces/ISynthetix.sol";


contract MyContract {

    // This should be instantiated with our ReadProxyAddressResolver
    // it's a ReadProxy that won't change, so safe to code it here without a setter
    // see https://docs.synthetix.io/addresses for addresses in mainnet and testnets
    IAddressResolver public synthetixResolver;

    constructor(IAddressResolver _snxResolver) public {
        synthetixResolver = _snxResolver;
    }

    function synthetixExchange(bytes32 src, uint amount, bytes32 dest) external {)
      ISynthetix synthetix = synthetixResolver.getAddress("Synthetix");
      require(synthetix != address(0), "Synthetix is missing from Synthetix resolver");

      // This check is what synthetix.exchange() will perform, added here for explicitness
      require(!synthetix.isWaitingPeriod(src), "Cannot exchange during the waiting period");

      // Exchange for msg.sender = address(MyContract)
      synthetix.exchange(src, amount, dest);

      // Note: due to Fee Reclamation in SIP-37, the following actions will fail if attempted in the
      // same block (the waiting period for the "to" synth must first expire)
        // synthetixResolver.getSynth(dest).transfer(address(0), 1e12)
        // synthetix.exchange(dest, 1e12, "sBTC");
        // synthetix.settle(dest);
    }

    function synthetixExchangeOnBehalf(address user, bytes32 src, uint amount, bytes32 dest) external {
        ISynthetix synthetix = synthetixResolver.getAddress("Synthetix");
        require(synthetix != address(0), "Synthetix is missing from Synthetix resolver");

        // This check is what synthetix.exchange() will perform, added here for explicitness
        require(!synthetix.isWaitingPeriod(src), "Cannot exchange during the waiting period");

        // Note: this will fail if `DelegateApprovals.approveExchangeOnBehalf(address(MyContract))` has
        // not yet been invoked by the user
        synthetix.exchangeOnBehalf(user, src, amount, dest);

        // Note: due to Fee Reclamation in SIP-37, the following actions will fail if attempted in the
        // same block (the waiting period for dest must first expire)
          // synthetixResolver.getSynth(dest).transferFrom(user, address(0), 1e12)
          // synthetix.exchangeOnBehalf(user, dest, 1e12, "sBTC");
          // synthetixResolver.getAddress("Exchanger").settle(user, dest)
    }
}