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 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)

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 = 3; // ropsten, (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 = 'ropsten';
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)
    }
}