Virtual Synths (vSynths)¶
SIP-89 introduced the concept of virtual synths. That is, upon exchanging a new ERC20 contract is created with virtual synths issued 1:1 representing a claim on those underlying synths. These virtual synths can be split up and transferred to any other wallet. Once the fee reclamation waiting period has expired (via SystemSettings.waitingPeriodSecs
), anyone can settle the virtual synths, burning them and transferring the holder their proportion of the synths from the settled trade.
Alternative Implementations
The exchangeWithVirtual
function creates and returns an ERC20 of Virtual Synths but strictly this is not necessary. Smart contract authors can simply exchange with Synthetix as a contract and manage the underlying synth distribution themsevles. Curve for instance with their Cross Asset Swaps did just this, using an NFT to hold the underlying synths instead of an ERC20 (see https://github.com/curvefi/curve-cross-asset-swaps/tree/master/contracts)
Virtual Synth API¶
There are two steps to Virtual Synths
- Create the virtual synth contract via
Synthetix.exchangeWithVirtual()
- this function outputs the newVirtualSynth
contract address for the next step - Once
VirtualSynth.secsLeftInWaitingPeriod
is0
(and it'sreadyToSettle
), invokeVirtualSynth.settle(address)
to burn the virtual synths and transfer the proportion of underlying synths to theaddress
.
1. Creation of Virtual Synth Contract¶
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 isSynthetix
. 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 synth |
address recipient |
address virtualSynth |
bytes32 currencyKey |
uint amount |
---|---|---|---|---|---|---|
VirtualSynthCreated |
Exchanger |
Proxy<dest> |
msg.sender (or user ) |
the new VirtualSynth contract address |
the synth key that is being virtualized | the amount issued |
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 |
Example Transactions on Mainnet¶
2. Settlement¶
Contract¶
VirtualSynth: This address is unique to each exchange. It is returned as the second part of the tuple returned from exchangeWithVirtual():(uint amountReceived, address vSynth)
. It is also emitted in the VirtualSynthCreated
event from the transaction above (see address vSynth
).
Target contract (ABI): VirtualSynth
Methods¶
Multiple Invocations
Because Virtual Synths are an ERC20, they can be distributed to any number of other accounts. However, the ERC20 contract itself must be settled once for all holders. This is done on the first invocation of VirtualSynth.settle(address account)
. Thus more gas is paid for the first invocation that subsequent ones.
Events Emitted¶
On a successful transaction, the following events occur:
For the first settlement of the entire VirtualSynth
contract:
name | emitted on | address account |
bytes32 src |
uint amount |
bytes32 dest |
uint reclaim |
uint rebate |
uint srcRoundIdAtPeriodEnd |
uint destRoundIdAtPeriodEnd |
uint exchangeTimestamp |
---|---|---|---|---|---|---|---|---|---|---|
ExchangeEntrySettled |
Exchanger |
msg.sender (or user ) |
src |
fromAmount |
dest |
reclaimedAmount if any |
rebateAmount if any |
the roundId for rate of src synth at waiting period expiry |
the roundId for rate of dest synth at waiting period expiry |
the timestamp of the exchange |
name | emitted on | uint totalSupply |
uint amountAfterSettled |
---|---|---|---|
Settled |
VirtualSynth |
The totalSupply of the virtual synth | The amount of the synth remaining after settlement (after reclaims removed or rebates added) |
Once the Virtual contract is settled, individual account
holders see the following events:
name | emitted on | address from |
address to |
uint value |
---|---|---|---|---|
Transfer |
Proxy<src> |
VirtualSynth |
account |
The user is sent their proportionate amount of synths |
name | emitted on | address from |
address to |
uint value |
---|---|---|---|---|
Transfer |
VirtualSynth |
account |
0x0 |
The user's vSynths are burned |
Example Transactions on Mainnet¶
Code Snippets¶
Exchanging sUSD for sBTC using vSynths
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 |
|