Skip to content

Staking: Open a Position

SNX stakers (aka minting, aka issuing) lock their SNX into the Synthetix protocol and take on a debt position (that is, a percentage) in the shared pool of the combined USD value of all synths (Synthetix.totalIssuedSynthsExcludingEtherCollateral()). Upon staking, they are issued sUSD that represents their current debt position in USD. However, as prices of underlying synths fluctuate with oracle updates, the size of the debt pool fluctuates, meaning that the staker's debt decouples from the amount of sUSD that was issued.

To account for the risk stakers take on by being exposed to a shared debt pool, they are rewarded each week in the form of sUSD trading fees and SNX inflationary rewards (see incentives for more information).

Via the contracts, the process is as follows:

Issuance API

To issue sUSD in Mintr, this is how they perform the task:

Contract

Use the Proxies

Note: The transaction's to parameter can be to either the proxy or the underlying, however two things are worth noting:

  1. the underlying is subject to change (and does most releases); and
  2. the events will always be emitted on the proxy, regardless of the to parameter in the transaction.

For best results, always interact with the proxy using the ABI of the underlying.

Destination contract (address): ProxyERC20 (preferred) or ProxySynthetix (deprecated, see this notice)

Target contract (ABI): Synthetix

Methods

Events Emitted

On a successful transaction, the following events occur:

name emitted on address from address to uint value
Transfer ProxysUSD 0x0 msg.sender (or user) amount of sUSD
name emitted on address account uint value
Issued ProxysUSD msg.sender (or user) amount
name emitted on address account uint debtRatio uint debtEntryIndex uint feePeriodStartingDebtIndex
IssuanceDebtRatioEntry FeePool msg.sender (or user) debtRatio debtEntryIndex feePeriodStartingDebtIndex

Examples from Mainnet

  • ProxySynthetix.issueSynths(1e18)
  • ProxySynthetix.issueMaxSynths()

Code Snippets

Staking (Minting/Issuing)

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

(async () => {
  try {
    // send transaction
    const txn = await snxjs.Synthetix.issueMaxSynths();

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

(async () => {
  try {
    // send transaction
    const txn = await Synthetix.issueMaxSynths();
    // 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
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 synthetixIssue() external {
      ISynthetix synthetix = synthetixResolver.getAddress("Synthetix");
      require(synthetix != address(0), "Synthetix is missing from Synthetix resolver");

      // Issue for msg.sender = address(MyContract)
      synthetix.issueMaxSynths();
    }

    function synthetixIssueOnBehalf(address user) external {
        ISynthetix synthetix = synthetixResolver.getAddress("Synthetix");
        require(synthetix != address(0), "Synthetix is missing from Synthetix resolver");

        // Note: this will fail if `DelegateApprovals.approveIssueOnBehalf(address(MyContract))` has
        // not yet been invoked by the `user`
        synthetix.issueMaxSynthsOnBehalf(user);
    }
}