Skip to content

rayedsikder/zil-dex-router

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Xcademy DEX Smart Contracts

Sections below describes the following :

  1. The purpose of contract
  2. Structure and specifications
  3. Local build environment
  4. Running unit tests for the contracts

Table of Content

Overview

Contract Name File and Location Description
FungibleToken FungibleToken.scilla A ZRC-2 for fungible token contract for XCAD tokens
FungibleToken With Dex Whitelisting XcadCC_FungibleToken.scilla A ZRC-2 for fungible token contract for XCAD CC tokens. This includes features for DEX whitelisting and BatchTransfer of tokens to multiple addresses. Documentation can be found here.
FungibleToken With Dex Whitelisting, Burnable, Mintable XcadCC_FungibleToken_V2.scilla A ZRC-2 for fungible token contract for XCAD CC tokens. This includes features for DEX whitelisting and BatchTransfer of tokens to multiple addressed, Minatble, Burnable and Minters List. Documentation can be found here.
FungibleToken With Dex Whitelisting, Burnable, Mintable, Sell On Fee XcadCC_FungibleToken_V3.scilla A ZRC-2 for fungible token contract for XCAD CC tokens. This includes features for DEX whitelisting and BatchTransfer of tokens to multiple addressed, Minatble, Burnable, Minters List and Sell On Fee. Documentation can be found here.
DEX_Xcad_Proxy DEX_Xcad_Proxy.scilla It is a proxy contract that sits on top of the DEX_Xcad contract. Any call to the DEX_Xcad contract must come from DEX_Xcad_Proxy. This contract facilitates upgradeability of the DEX_Xcad contract in case a bug is found.
DEX_Xcad DEX_Xcad.scilla It is the main contract that keeps track of DEX on Xcademy.
DEX_Xcad_Proxy V2 Sell On Fees Feature DEX_Xcad_Proxy_V2.scilla It is a proxy contract that sits on top of the DEX_Xcad contract. Any call to the DEX_Xcad contract must come from DEX_Xcad_Proxy. This contract facilitates upgradeability of the DEX_Xcad contract in case a bug is found.
DEX_Xcad V2 Sell On Fees Feature DEX_Xcad_V2.scilla It is the main contract that keeps track of DEX on Xcademy.

Note : It is recommended to use multi-sig wallets for ownership of DEX, Proxy and Fungible Tokens.

Design decision

Clean logical seperation of proxy and implementation function

Proxy, once deployed, should not be changed. As such. the proxy should not perform any additional logic beyond transfering of calls to the implementation. Any roles or permissions check should be strictly done on implementation.

By consolidating all logical checks in the implementation, the benefits are

  • Possbility of making logical modification in future implementation
  • Avoid conflicting check between proxy and implementation

Units

Units in the DEX are based on the smallest units of each tokens. This avoids the handling of any floating points.

Minimal liquditytra

For creation of new pool, a minimal liqudity of at least 100(in smallest unit value for the token) is enforced. This can be modified via SetTokenMinLiquidity transition. This is to offset any rounding issues when liquidity of the pool is low.

General Flow

Users and dApps may use the DEX_Xcad_Proxy contract to swap between any 2 tokens without any middlemen. Because the swap is done against the liquidity pools, there is no need to wait for a counterparty, and transactions can be done completely on-chain.

Roles and Privileges

The table below list the different roles defined in the contract.

Name Description & Privileges
admin The admin of proxy contract for admin functionalities.
owner The owner who own the DEX contract.
treasury_fees_address The address which receives the treasury amount collected in trades.

Fees

Liquidity provider fees

There is a 0.3% fee(configurable) for swapping tokens. This fee is split by liquidity providers proportional to their contribution to liquidity reserves. Swapping fees are immediately deposited into liquidity reserves.

Treasury Fees

The dex contract allows for charging an additional fee per swap transaction, which goes to the dex treasury. Such fees (configuration) will be deducted from the input token amount(applies to both case when it is limit or exact amount). The contract owner of the dex can initiate withdrawal of the treasury fees to a designated address treasury_fees_address at any point in time.

Treasury Fee Calculation

basis point denon in dex = 10000
pool fee = 2000 (20%)
treasury fee = 1000 (10%)

Based on above numbers :
pool_fee = 8000
treasury_fee = 1000
after_total_fee = fee_denom - (pool_fee + treasury_fee) = 7000

Below example illustrates the calculation(token0 and token1 are based on two decimal points)

Swap 100 token0 into token 1. (pool token0 reserve = 1000.00, token1 reserve = 1000.00)

With fee as 7000 calculate output amount
calculated_amount = 65.42
treasury_fee_amount = 10 % of exact_amount = 10 % of 100.00 = 10.00

amount to add in reserve amount(token0) = 100.00 - 10.00 = 90.00
updated token0 pool reserve = 1000.00 + 90.00 = 1090.00
updated token1 pool reserve = 1000.00 - calculated_amount = 1000.00 - 65.42 = 934.58
treasury_fee_amount(token0) = 10.00

Swap some token0 into 100 token 1. (pool token0 reserve = 1000.00, token1 reserve = 1000.00)

With fee as 7000 calculate output amount
calculated_amount = 158.73
treasury_fee_amount = 10 % of calculated_amount = 10 % of 158.73 = 15.87

amount to add in reserve amount(token0) = 158.73 - 15.87 = 142.86
updated token0 pool reserve = 1000.00 + 142.86 = 1142.86
updated token1 pool reserve = 1000.00 - exact_amount = 1000.00 - 100.00 = 900.00
treasury_fee_amount(token0) = 15.87

Sell On Fees DEX V2

The DEX contract V2 supports tokens sell on fees feature. This feature is implemented in a similar way to NFT roalty fees. This fee as the name implies only applies to the selling of a token, it does not aply to the buying of the tokens. This fee is an additional fee to the exisiting Swap fees in the DEX V1. The fees are accumulated in the DEX V2 contract. The contract owner of the DEX can initiate withdrawal of this Sell On Fee to a designated address sell_fee_recipient at any point in time. The withrawal can also be initiated by the designated sell_fee_recipient at any point in time.

Fee Settings:

The Sell On Fee rate is defined in the Content Creator Token smart contract. Each CC Token that wants to charge sell on fee will have these two fields sell_fee_bps sell on fee rate in bps e.g. 500 for 5%. Valid range is 0 - 10000 sell_fee_recipient Address of account to receive sell on fee

The CC Token Contract owner can update the settings by calling SetSellFeeBPS SetSellFeeRecipient

Fee Calculation:

DEX V2 smart contract dectects when it is a sell, i.e. looking at the Input Token it reads the sell_fee_bps from the CCT contract if sell_fee_bps is not found then sell on fee is taken to be 0 The DEX contract then calculate the fee sell fee amount = swap amount * sell_fee_bps / 10000

Fee Storage:

The sell on fees are accumulated in the DEX V2 smart contract, not sent to receiver on every sell. sell_fee_balances hold sell on fees

Fee Withdrawal:

The Sell on Fees can be withdrawn by DEX V2 contract_owner or the sell_on_fee_recipient Contract_Owner can call WithdrawSellFee(initiator : ByStr20, token_address : ByStr20) to send sell on fee for the given Token to the sell_fee_recipient defined in the Token contract The DEX V 2 contract: reads fee amount accumulated in sell_on_fee_balances reads sell_fee_recipient from CC Token contract transfers the fee to the recipient

BatchWithdrawSellFees(initiator: ByStr20, token_list: List (ByStr20)) to send sell on fees for a list of tokens

Sell_Fee_Recipient can also initiate sell fee withdraw, can call WithdrawSellFeeByRecipient(initiator : ByStr20, token_address : ByStr20) to send sell on fee for the given token to the recipient

Fees Structure in DEX V2:

So in the DEX V2 smart contract we have this fee structure

  1. Swap Fee this is the existing fee in DEX V1, it consists of LPProvider fee and Treasury Fee, this fee applies to all swaps ( both buy and sell)

  2. Sell On Fee, this applies only to Sell of tokens that has this sell on fee feature.

Example Fees: If the fee settings are: Liquidity Provider Fee = 16 Treasury Fee = 14 Sell On Fee = 500

For or a sell of of a Content Creator Token we may have these fees

0.16% of swap amount goes to Liquidity Pool
0.14% of swap amount goes to Treasury
5.00% of swap amount goes to Sell_Fee_Balance

For a buy of Content Creator token

0.16% of swap amount goes to Liquidity Pool
0.14% of swap amount goes to Treasury

For buy or sell of other tokens - non sell on fee tokens

0.16% of swap amount goes to Liquidity Pool
0.14% of swap amount goes to Treasury

Swap Scenarios :

token0 <=> token1

  1. DirectSwapExactToken0ToToken1 token0,token1 (input is exact amount and output is limit amount)

  2. DirectSwapToken0ToExactToken1 token0,token1 (input is limit amount and output is exact amount)

  3. DirectSwapExactToken0ToToken1 token1,token0 (input is exact amount and output is limit amount)

  4. DirectSwapToken0ToExactToken1 token1,token0 (input is limit amount and output is exact amount)

Immutable Parameters

The table below lists the parameters that are defined at the contract deployment time and hence cannot be changed later on.

DEX_Xcad_Proxy Contract

Name Type Description
initial_owner ByStr20 The initial owner of the contract.
initial_implementation ByStr20 The initial implementation of the DEX_Xcad contract.

DEX_Xcad Contract

Name Type Description
initial_owner ByStr20 The initial admin of the contract.
initial_pool_fee Uint256 The initial fee is set
initial_proxy_address ByStr20 The initial address of the DEX_Xcad_Proxy contract
initial_treasury_fees_address ByStr20 The initial designated address for withdrawal of treasury fees collected.
initial_treasury_fee Uint256 This includes percentage to be deducted from exact amount provided in basis point(10000) eg; if treasury fee to deduct is 0.01 % then initial_treasury_fee to be passed should be 1. If no treasury fee is to be applied then keep initial_treasury_fee as 0.

Mutable Fields

The table below presents the mutable fields of the contract and their initial values.

DEX_Xcad_Proxy

Name Type Initial Value Description
implementation ByStr20 initial_implementation Curent implementation of main contract.
old_implementation ByStr20 initial_implementation Older implementation of main contract required for upgrading.
owner ByStr20 initial_owner Admin of DEX_Xcad_Proxy for changing implementation contracts.
pending_owner ByStr20 zil_address Staged Admin by Current admin while transferring ownership

DEX_Xcad

Name Type Initial Value Description
pools Map ByStr20 Pool Emp ByStr20 Pool Map of Pools.
xpools Map String XPool Emp String XPool Map of XPools. XPool stores non-zil related pool reserves.
balances Map ByStr20 (Map ByStr20 Uint128) Emp ByStr20 (Map ByStr20 Uint128) Map of balances.
xbalances Map String (Map ByStr20 (Map ByStr20 Uint128)) Emp String (Map ByStr20 (Map ByStr20 Uint128) Map of xbalances. Related to token to token swap which does not involve zils.
total_contributions Map String (Map ByStr20 Uint128) Emp String (Map ByStr20 Uint128) Map of total contributions for non zil related pools.
xtotal_contributions Map ByStr20 Uint128 Emp ByStr20 Uint128 Map of total contributions.
output_after_total_fee Uint256 fee_denom minus (initial_pool_fee plus treasury_fee) Output after all fee.
treasury_fee Uint256 initial_treasury_fee Treasury fee to be applied on exact amount input.
owner ByStr20 initial_owner Current owner.
pending_owner ByStr20 zil_address Pending owner.
token_pairs Map ByStr20 (Map ByStr20 Uint128) Emp ByStr20 (Map ByStr20 Uint128) Map of token pairs.
paused Bool True Status of whether the contract is paused.
treasury_balances Map ByStr20 Uint128 Emp ByStr20 Uint128 Map of token address and treasury amount

Events

Frontend dApps may listen to the following smart contract events to watch for changes in state due to user interaction.

FeeSet

The FeeSet is emitted when the contract owner sets a new fee. It is emitted even if the new fee is the same as the old fee.

Parameter Type Description
fee Uint256 The fee in basis points (1 = 0.01%)

OwnershipTransferred

The OwnershipTransferred is emitted when the existing contract owner transfers ownership to a new address.

Parameter Type Description
new_owner ByStr20 The address of the new owner

PoolCreated

The PoolCreated event is emitted when liquidity is first added for a ZRC-2 token.

Pools are indexed by the ZRC-2 token's smart contract address, emitted in the parameter, pool.

Parameter Type Description
pool ByStr20 The ZRC-2 token address for the pool that was created

XPoolCreated

The XPoolCreated event is emitted when liquidity is first added for a pair of ZRC-2 tokens.

XPools are indexed by the concatenation of ZRC-2 token's smart contract addresses delimited by comma, emitted in the parameter, xpool.

Parameter Type Description
address ByStr20 Address of pool creator
token0_address ByStr20 The ZRC-2 token0 address for the xpool that was created
token1_address ByStr20 The ZRC-2 token1 address for the xpool that was created
token0_amount Uint128 The token0 amount of tokens contributed to xpool
token1_amount Uint128 The token1 amount of tokens contributed to xpool

AddNewTokenLiquidity

The AddNewTokenLiquidity event is emitted when liquidity has been added in xpool.

Parameter Type Description
address ByStr20 Address of pool creator
token0_address ByStr20 The ZRC-2 token0 address for the liquidity pool contribution
token1_address ByStr20 The ZRC-2 token1 address for the liquidity pool contribution
token0_contribution Uint128 The token0 amount of tokens contributed to xpool
token1_contribution Uint128 The token1 amount of tokens contributed to xpool

Mint

The Mint event is emitted when liquidity is added to a pool and "liquidity tokens" are "minted".

The amount of liquidity tokens minted is calculated by taking the ratio of pool tokens added as compared to that already residing in the pool.

The share of liquidity contribution for a pool can then be found by dividing amount with the smart contract variable total_contributions[token_address].

Parameter Type Description
pool ByStr20 The token address of the pool that has had liquidity added to
address ByStr20 The address that contributed liquidity
amount Uint128 The amount of liquidity contributed

Burnt

The Burnt event is emitted when liquidity is removed from a pool and "liquidity tokens" are "burnt".

The amount of liquidity tokens burnt is calculated by taking the ratio of pool tokens removed as compared to the total pool tokens residing in the pool.

The share of liquidity contribution removed for the address can be found by dividing amount with the smart contract variable total_contributions[token_address].

Parameter Type Description
pool ByStr20 The token address of the pool that has had liquidity removed
address ByStr20 The address that removed liquidity
amount Uint128 The amount of liquidity removed

BurntXPool

The BurntXPool event is emitted when liquidity is removed from a xpool and "liquidity tokens" are "burnt".

The amount of liquidity tokens burnt is calculated by taking the ratio of xpool tokens removed as compared to the total xpool tokens residing in the xpool.

pool: xpool_t0_t1_key; address: initiator; token0_amount: token0_contribution_amount

Parameter Type Description
pool String The string concatenation of token0 address, token1 address delimited by comma of the xpool that has had liquidity removed
address ByStr20 The address that removed liquidity
token0_amount Uint128 The amount of liquidity removed

TransferZils

The TransferZils event is emitted when ZILs from old dex is moved to new dex".

Parameter Type Description
new_implementation ByStr20 The address of dex contract which received ZILs.
initiator ByStr20 The address that invoked the TransferZils transition in DEX
amount Uint128 The amount of ZILs moved

TransferTokens

The TransferTokens event is emitted when tokens from Pool in old dex is moved to new dex".

Parameter Type Description
new_implementation ByStr20 The address of dex contract which received ZILs.
initiator ByStr20 The address that invoked the TransferTokens transition in DEX
amount Uint128 The amount of tokens moved
token_address ByStr20 The address of token moved

TransferXTokens

The TransferXTokens event is emitted when tokens from XPool in old dex is moved to new dex".

Parameter Type Description
new_implementation ByStr20 The address of dex contract which received ZILs.
initiator ByStr20 The address that invoked the TransferXTokens transition in DEX
t0_amount Uint128 The token0 amount moved
t1_amount Uint128 The token0 amount moved
token0_address ByStr20 The address of token0 moved
token1_address ByStr20 The address of token1 moved

Swapped

The Swapped event is emitted when a swap is made in a pool.

Since pools are already balanced against ZIL, all events have a zil_in and zil_out amount to signify the amount of ZIL sent to or received from the pool during the swap respectively.

All events also have the token_in and token_out to signify the corresponding token amounts sent to or received from the pool.

The address of the token sent or received in token_in and token_out is given by token_address.

Note that if zil_in is non-zero, then zil_out will always be zero, and vice versa. The same goes for token_in and token_out.

Parameter Type Description
pool ByStr20 The token address of the pool where the swap took place
address ByStr20 The address that initiated the swap
zil_in Uint128 The amount of zil transferred into the pool for the swap in QA
zil_out Uint128 The amount of zil removed from the pool for the swap in QA
token_in Uint128 The amount of tokens transferred into the pool for the swap
token_out Uint128 The amount of tokens removed rrom the pool for the swap

XSwapped

The XSwapped event is emitted when a swap is made in a xpool(token to token pool).

All events also have the token_in and token_out to signify the corresponding token amounts sent to or received from the xpool.

The address of the token sent or received in token_in and token_out is given by token_address.

Parameter Type Description
pool String The concatenated string of token0 address and token1 address delimited by a comma for pool where the swap took place
address The address that initiated the swap.
token0_address ByStr20 The address of token0
token0_address ByStr20 The address of token1
input Coins The ADT that includes token address, input exact amount for swap
output Coins The ADT that includes token address, calculated output amount for swap

TokenPairAdded

The TokenPairAdded event is emitted when a new token pair is added in dex.

Parameter Type Description
token0_address ByStr20 The address of token0
token0_address ByStr20 The address of token1

TokenPairRemoved

The TokenPairRemoved event is emitted when a token pair is removed dex.

Parameter Type Description
token0_address ByStr20 The address of token0
token0_address ByStr20 The address of token1

Transitions

Note that each of the transitions in the DEX_Xcad contract takes initiator as a parameter which as explained above is the caller that calls the DEX_Xcad_Proxy contract which in turn calls the DEX_Xcad contract.

Note: No transition in the DEX_Xcad contract can be invoked directly. Any call to the DEX_Xcad contract must come from the DEX_Xcad_Proxy contract.

Transition Name Params Callable when paused? Callable when not paused?
AddTokenLiquidity token0_address : ByStr20,
token1_address : ByStr20,
token0_amount : Uint128,
min_token0_contribution_amount : Uint128,
max_token1_contribution_amount : Uint128,
deadline_block : BNum
✔️
RemoveTokenLiquidity token0_address : ByStr20,
token1_address : ByStr20,
token0_contribution_amount : Uint128,
min_token0_amount : Uint128,
min_token1_amount : Uint128,
deadline_block : BNum
✔️
DirectSwapTokens0ToExactTokens1 token0_address : ByStr20,
token1_address : ByStr20,
token0_amount : Uint128,
token1_amount : Uint128,
deadline_block : BNum,
recipient_address : ByStr20
✔️
DirectSwapExactTokens0ToTokens1 token0_address : ByStr20,
token1_address : ByStr20,
token0_amount : Uint128,
token1_amount : Uint128,
deadline_block : BNum,
recipient_address : ByStr20
✔️
AddLiquidity token_address : ByStr20,
min_contribution_amount : Uint128,
max_token_amount : Uint128,
deadline_block : BNum
✔️
RemoveLiquidity token_address : ByStr20,
contribution_amount : Uint128,
min_zil_amount : Uint128,
min_token_amount : Uint128,
deadline_block : BNum
✔️
SwapExactZILForTokens token_address : ByStr20,
min_token_amount : Uint128,
deadline_block : BNum,
recipient_address : ByStr20
✔️
SwapExactTokensForZIL token_address : ByStr20,
token_amount : Uint128,
min_zil_amount : Uint128,
deadline_block : BNum,
recipient_address : ByStr20
✔️
SwapZILForExactTokens token_address : ByStr20,
token_amount : Uint128,
deadline_block : BNum,
recipient_address : ByStr20
✔️
SwapTokensForExactZIL token_address : ByStr20,
max_token_amount : Uint128,
zil_amount : Uint128,
deadline_block : BNum,
recipient_address : ByStr20
✔️
SwapExactTokensForTokens token0_address : ByStr20,
token1_address : ByStr20,
token0_amount : Uint128,
min_token1_amount : Uint128,
deadline_block : BNum,
recipient_address : ByStr20
✔️
SwapTokensForExactTokens token0_address : ByStr20,
token1_address : ByStr20,
max_token0_amount : Uint128,
token1_amount : Uint128,
deadline_block : BNum,
recipient_address : ByStr20
✔️
UpgradePool token_address: ByStr20 ✔️
UpgradeXPool token0_address: ByStr20,
token1_address: ByStr20
✔️
PopulatePool initiator:ByStr20,
token_address: ByStr20,
zil_reserve: Uint128,
token_reserve: Uint128
✔️
PopulateXPool initiator:ByStr20,
token0_address: ByStr20,
token1_address: ByStr20,
token0_reserve: Uint128,
token1_reserve: Uint128
✔️
UpgradeBalances ✔️
UpgradeXBalances ✔️
UpgradeTotalContrib ✔️
UpgradeXTotalContrib ✔️
TransferZils ✔️
TransferTokens token_address: ByStr20 ✔️
TransferTreasuryTokens token_address: ByStr20 ✔️
TransferXTokens token0_address: ByStr20,
token1_address: ByStr20
✔️
Pause ✔️ ✔️
UnPause ✔️ ✔️
TransferOwnership new_owner : ByStr20 ✔️ ✔️
AcceptPendingOwnership ✔️ ✔️
AddTokenPair token0_address : ByStr20,
token1_address : ByStr20
✔️ ✔️
RemoveTokenPair token0_address : ByStr20,
token1_address : ByStr20
✔️ ✔️
SetFee new_pool_fee : Uint256, new_treasury_fee : Uint256 ✔️ ✔️
SetTreasuryFeesAddress new_treasury_fees_address : ByStr20 ✔️ ✔️
WithdrawTreasuryTokens token_address : ByStr20 ✔️ ✔️
BatchWithdrawTreasuryTokens token_list: List (ByStr20) ✔️ ✔️
WithdrawTreasuryZils ✔️ ✔️
UpgradeTreasuryBalances ✔️

Transitions DEX V2

Additional transitions for the Sell On Fee feature in DEX V2 contract

Transition Name Params Callable when paused? Callable when not paused?
WithdrawSellFee token_address : ByStr20 ✔️ ✔️
BatchWithdrawSellFees token_list: List (ByStr20) ✔️ ✔️
WithdrawSellFeeByRecipient token_address : ByStr20 ✔️ ✔️

All the transitions in the contract can be categorized into four categories:

  • Housekeeping Transitions: Meant to facilitate non-functional tasks of contract.
  • ZRC-2 < > ZRC-2 Transitions: Meant to facilitate basic functional tasks related to trading pair where both sides are ZRC-2 transitions.
  • ZIL < > ZRC-2 Transitions: Meant to facilitate basic functional tasks related to trading pair where one side is ZIL and other side is ZRC-2 transitions.
  • Upgrade Transitions: The transitions that allows to upgrade and populate mutable fieldswhile upgrading to other implementation of DEX_Xcad.
  • Callback Transitions: The transitions that are callback for standard ZRC2 transitions.

Each of these category of transitions are presented in further detail below.

Housekeeping Transitions

Name Description
Pause Change state of DEX_Xcad contract to be paused.
⚠️ Note: Only the dex owner can invoke this transition
UnPause Change state of DEX_Xcad contract to be un-paused.
⚠️ Note: Only the dex owner can invoke this transition.
TransferOwnership Change ownership of DEX to a new address.
⚠️ Note: Only the dex owner can invoke this transition
AcceptPendingOwnership Accept ownership of DEX contract.
TransferProxyOwnership Change the current pending_owner of the proxy contract.
⚠️ Note: Only the proxy admin can invoke this transition.
AcceptPendingProxyOwnership Accept ownership of Proxy contract.
AddTokenPair Add token pair to allow swap.
⚠️ Note: Only the dex owner can invoke this transition
RemoveTokenPair Add token pair to allow swap.
⚠️ Note: Only the dex owner can invoke this transition
SetFee Set fee for swap.
⚠️ Note: Only the dex owner can invoke this transition
SetTreasuryFeesAddress Set the designated address for treasury fees withdrawal.
⚠️ Note: Only the dex owner can invoke this transition

ZRC-2 < > ZRC-2 Transitions

The following are the public transitions that can be called via smart contract invocations. It involves trading pair where both sides are ZRC-2 tokens.

Each transition has a deadline_block parameter that can be used to set the block for which the signed transaction is no longer valid be executed by the Zilliqa blockchain.

This can be used to prevent a "transaction withholding attack" by miners, where a transaction can be withheld indefinitely, to only be confirmed when it may benefit other parties in ways unexpected or detrimental to the sender.

AddTokenLiquidity

This transition adds liquidity to the xpool(pool maintained for xcad LPs) for the ZRC-2 token given by token0_address and token1_address. Liquidity providers deposit token0 and token1 ZRC-2 tokens using the exchange rate of the liquidity pool (i.e. the ratios between the two tokens' reserve amounts) at the moment of the transition.

The token0 token0_amount sent is the exact amount of tokens that the sender wishes to add to the liquidity pool and it should be 50% of the total value that they wish to deposit into the pool.

Because the ratio of tokens in a liquidity pool can fluctutate between when the sender signs the transaction and when it is processed by the blockchain, the parameter bound max_token1_contribution_amount is used to bound the exchange rate. For the first liquidity provider, max_token1_contribution_amount is the exact amount of ZRC-2 tokens that will be deposited.

The min_token0_contribution_amount can be used to set the lower bound of the sender's the contribution share (given by min_token0_contribution_amount/xtotal_contributions[pool_address]) when the transaction is executed. For the first liquidity provider, min_token0_contribution_amount is ignored.

Note that liquidity providers should aim to deposit what they believe to be equal values of both token0 and token1 ZRC-2 tokens. While the initial exchange rate is set by the first liquidity provider that creates a pool, arbitrage traders will bring the prices to equilibrium at the expense of the initial liquidity provider(s), should this ratio be irreflective of their true value.

Parameter Type Description
token0_address ByStr20 The token0 token address of the xpool to add liquidity to
token1_address ByStr20 The token1 token address of the xpool to add liquidity to
_amount Uint128 The amount of ZIL to contribute to the pool, put it as zero
token0_amount Uint128 The amount of token0 to contribute to the xpool
min_token0_contribution_amount Uint128 The minimum liquidity tokens that needs to be minted
max_token1_contribution_amount Uint128 The maximum amount of ZRC-2 token to contribute to the xpool
deadline_block BNum The deadline that this transaction must be executed by

RemoveTokenLiquidity

This transition removes liquidity from the xpool for the ZRC-2 token0,token1 given by token0_address+token1_address. Liquidity providers can withdraw their share of token0 and token1 tokens based on the exchange rate of the liquidity pool (i.e. the ratios between the two tokens' reserve amounts) at the moment of the transition.

The token0_contribution_amount can be used to redraw all or some of the sender's tokens based on his previous contributions found in xbalances[token0_address+token1_address][token0_address][_sender].

Because the ratio of tokens in a liquidity pool can fluctutate between when the sender signs the transaction and when it is processed by the blockchain, the parameter bounds min_token0_amount and min_token1_amount is used to bound the exchange rate.

Parameter Type Description
token0_address ByStr20 The token0 token address of the pool to add liquidity to
token1_address ByStr20 The token1 token address of the pool to add liquidity to
token0_contribution_amount Uint128 The share of contribution to remove
min_token0_amount Uint128 The minimum amount of token0 to be withdrawn
min_token1_amount Uint128 The minimum amount of token1 tokens to be withdrawn
deadline_block BNum The deadline that this transaction must be executed by

DirectSwapTokens0ToExactTokens1

This transition swaps ZRC-2 tokens given by token0_address for an exact amount of another ZRC-2 token given by token1_address at the prevailing exchange rate that is determined by the constant product formula of the liquidity pools.

The maximum amount of token0 to be given for the swap is capped by token0_amount, which can be used to bound the swap exchange rate that may fluctuate from the time of the sender signs the transaction and when it is processed by the blockchain. The transaction reverts with an error RequestedRatesCannotBeFulfilled if the prevailing exchange rate during transaction execution does not allow this condition to be satisfied.

Parameter Type Description
token0_address ByStr20 The token address of the ZRC-2 token to send (sell)
token1_address ByStr20 The token address of the ZRC-2 token to take (buy)
token0_amount Uint128 The maximum amount of token0 to be sent (sold)
token1_amount Uint128 The exact amount of token1 to be taken (bought)
deadline_block BNum The deadline that this transaction must be executed by

DirectSwapExactTokens0ToTokens1

This transition swaps an exact amount of token0 tokens given by token0_address for another ZRC-2 token given by token1_address at the prevailing exchange rate that is determined by the constant product formula of the liquidity pools.

The minimum amount of token1 to be taken in return is given by token1_amount, which can be used to bound the swap exchange rate that may fluctuate from the time of the sender signs the transaction and when it is processed by the blockchain. The transaction reverts with an error RequestedRatesCannotBeFulfilled if the prevailing exchange rate during transaction execution does not allow this condition to be satisfied.

Parameter Type Description
token0_address ByStr20 The token address of the ZRC-2 token to send (sell)
token1_address ByStr20 The token address of the ZRC-2 token to take (buy)
token0_amount Uint128 The exact amount of token0 to be sent (sold)
token1_amount Uint128 The minimum amount of token1 to be taken (bought)
deadline_block BNum The deadline that this transaction must be executed by

ZIL < > ZRC-2 Transitions

The following are the public transitions that can be called via smart contract invocations. It involves trading pair where both one side is ZIL and other side is ZRC-2 token.

Each transition has a deadline_block parameter that can be used to set the block for which the signed transaction is no longer valid be executed by the Zilliqa blockchain.

This can be used to prevent a "transaction withholding attack" by miners, where a transaction can be withheld indefinitely, to only be confirmed when it may benefit other parties in ways unexpected or detrimental to the sender.

AddLiquidity

This transition adds liquidity to the pool for the ZRC-2 token given by token_address. Liquidity providers deposit ZIL and ZRC-2 tokens using the exchange rate of the liquidity pool (i.e. the ratios between the two tokens' reserve amounts) at the moment of the transition.

The ZIL _amount sent is the exact amount of ZIL that the sender wishes to add to the liquidity pool and it should be 50% of the total value that they wish to deposit into the pool.

Because the ratio of tokens in a liquidity pool can fluctutate between when the sender signs the transaction and when it is processed by the blockchain, the parameter bound max_token_amount is used to bound the exchange rate. For the first liquidity provider, max_token_amount is the exact amount of ZRC-2 tokens that will be deposited.

The min_contribution_amount can be used to set the lower bound of the sender's the contribution share (given by min_contribution_amount/total_contributions[pool_address]) when the transaction is executed. For the first liquidity provider, min_contribution_amount is ignored.

Note that liquidity providers should aim to deposit what they believe to be equal values of both ZIL and the ZRC-2 tokens. While the initial exchange rate is set by the first liquidity provider that creates a pool, arbitrage traders will bring the prices to equilibrium at the expense of the initial liquidity provider(s), should this ratio be irreflective of their true value.

Parameter Type Description
token_address ByStr20 The token address of the pool to add liquidity to
_amount Uint128 The amount of ZIL to contribute to the pool
min_contribution_amount ByStr20 The minimum liquidity tokens that needs to be minted
max_token_amount Uint128 The maximum amount of ZRC-2 token to contribute to the pool
deadline_block BNum The deadline that this transaction must be executed by

RemoveLiquidity

This transition removes liquidity from the pool for the ZRC-2 token given by token_address. Liquidity providers can withdraw their share of ZIL and ZRC-2 tokens based on the exchange rate of the liquidity pool (i.e. the ratios between the two tokens' reserve amounts) at the moment of the transition.

The contribution_amount can be used to redraw all or some of the sender's tokens based on his previous contributions found in balances[pool_address][_sender].

Because the ratio of tokens in a liquidity pool can fluctutate between when the sender signs the transaction and when it is processed by the blockchain, the parameter bounds min_zil_amount and min_token_amount is used to bound the exchange rate.

Parameter Type Description
token_address ByStr20 The token address of the pool to add liquidity to
contribution_amount Uint128 The share of contribution to remove
min_zil_amount ByStr20 The minimum amount of ZIL to be withdrawn
min_token_amount Uint128 The minimum amount of ZRC-2 tokens to be withdrawn
deadline_block BNum The deadline that this transaction must be executed by

SwapExactZILForTokens

This transition swaps an exact amount of Zilliqa tokens (ZIL) for ZRC-2 tokens given by token_address at the prevailing exchange rate that is determined by the constant product formula of the liquidity pool.

The minimum amount of ZRC-2 tokens to be taken in return is given by min_token_amount, which can be used to bound the swap exchange rate that may fluctuate from the time of the sender signs the transaction and when it is processed by the blockchain. The transaction reverts with an error RequestedRatesCannotBeFulfilled if the prevailing exchange rate during transaction execution does not allow this condition to be satisfied.

Parameter Type Description
token_address ByStr20 The token address of the pool to add liquidity to
_amount Uint128 The exact amount of ZIL to be sent (sold)
min_token_amount Uint128 The minimum amount of ZRC-2 tokens to be taken (bought)
deadline_block BNum The deadline that this transaction must be executed by

SwapExactTokensForZIL

This transition swaps an exact amount of ZRC-2 tokens given by token_address for Zilliqa tokens (ZIL) at the prevailing exchange rate that is determined by the constant product formula of the liquidity pool.

The minimum amount of ZIL to be taken in return is given by min_zil_amount, which can be used to bound the swap exchange rate that may fluctuate from the time of the sender signs the transaction and when it is processed by the blockchain. The transaction reverts with an error RequestedRatesCannotBeFulfilled if the prevailing exchange rate during transaction execution does not allow this condition to be satisfied.

Parameter Type Description
token_address ByStr20 The token address of the pool to add liquidity to
token_amount Uint128 The exact amount of ZRC-2 tokens to be sent (sold)
min_zil_amount Uint128 The minimum amount of ZIL tokens to be taken (bought)
deadline_block BNum The deadline that this transaction must be executed by

SwapZILForExactTokens

This transition swaps Zilliqa tokens (ZIL) for an exact amount of ZRC-2 tokens given by token_address at the prevailing exchange rate that is determined by the constant product formula of the liquidity pool.

The maximum amount of ZIL to be given for the swap is capped by _amount, which can be used to bound the swap exchange rate that may fluctuate from the time of the sender signs the transaction and when it is processed by the blockchain. The transaction reverts with an error RequestedRatesCannotBeFulfilled if the prevailing exchange rate during transaction execution does not allow this condition to be satisfied.

Parameter Type Description
token_address ByStr20 The token address of the pool to add liquidity to
_amount Uint128 The maximum amount of ZIL to be sent (sold)
token_amount Uint128 The exact amount of ZRC-2 tokens to be taken (bought)
deadline_block BNum The deadline that this transaction must be executed by

SwapTokensForExactZIL

This transition swaps ZRC-2 tokens given by token_address for an exact amount of Zilliqa tokens (ZIL) at the prevailing exchange rate that is determined by the constant product formula of the liquidity pool.

The maximum amount of ZRC-2 tokens to be given for the swap is capped by max_token_amount, which can be used to bound the swap exchange rate that may fluctuate from the time of the sender signs the transaction and when it is processed by the blockchain. The transaction reverts with an error RequestedRatesCannotBeFulfilled if the prevailing exchange rate during transaction execution does not allow this condition to be satisfied.

Parameter Type Description
token_address ByStr20 The token address of the pool to add liquidity to
max_token_amount Uint128 The maximum amount of ZRC-2 tokens to be sent (sold)
zil_amount Uint128 The exact amount of ZIL tokens to be taken (bought)
deadline_block BNum The deadline that this transaction must be executed by

SwapExactTokensForTokens

This transition swaps an exact amount of ZRC-2 tokens given by token_address0 for another ZRC-2 token given by token_address1 at the prevailing exchange rate that is determined by the constant product formula of the liquidity pools.

The minimum amount of token1 to be taken in return is given by min_token1_amount, which can be used to bound the swap exchange rate that may fluctuate from the time of the sender signs the transaction and when it is processed by the blockchain. The transaction reverts with an error RequestedRatesCannotBeFulfilled if the prevailing exchange rate during transaction execution does not allow this condition to be satisfied.

Parameter Type Description
token0_address ByStr20 The token address of the ZRC-2 token to send (sell)
token1_address ByStr20 The token address of the ZRC-2 token to take (buy)
token0_amount Uint128 The exact amount of token0 to be sent (sold)
min_token1_amount Uint128 The minimum amount of token1 to be taken (bought)
deadline_block BNum The deadline that this transaction must be executed by

SwapTokensForExactTokens

This transition swaps ZRC-2 tokens given by token_address0 for an exact amount of another ZRC-2 token given by token_address1 at the prevailing exchange rate that is determined by the constant product formula of the liquidity pools.

The maximum amount of token0 to be given for the swap is capped by max_token0_amount, which can be used to bound the swap exchange rate that may fluctuate from the time of the sender signs the transaction and when it is processed by the blockchain. The transaction reverts with an error RequestedRatesCannotBeFulfilled if the prevailing exchange rate during transaction execution does not allow this condition to be satisfied.

Parameter Type Description
token0_address ByStr20 The token address of the ZRC-2 token to send (sell)
token1_address ByStr20 The token address of the ZRC-2 token to take (buy)
max_token0_amount Uint128 The maximum amount of token0 to be sent (sold)
token1_amount Uint128 The exact amount of token1 to be taken (bought)
deadline_block BNum The deadline that this transaction must be executed by

Upgrade Transitions

Name Description
UpgradePool Callable to upgrade Pool to new implementation.
⚠️ Note: Only the dex owner can invoke this transition
UpgradeXPool Callable to upgrade XPool to new implementation.
⚠️ Note: Only the dex owner can invoke this transition
PopulatePool Populate the Pool in new implementation, called on new implementation by old implementation automatically when UpgradePool is called on Proxy contract.
⚠️ Note: Only the dex owner can invoke this transition
PopulateXPool Populate the XPool in new implementation, called on new implementation by old implementation automatically when UpgradexPool is called on Proxy contract.
⚠️ Note: Only the dex owner can invoke this transition
UpgradeBalances Callable to upgrade Balances to new implementation.
⚠️ Note: Only the dex owner can invoke this transition
UpgradeXBalances Callable to upgrade xBalances to new implementation.
⚠️ Note: Only the dex owner can invoke this transition
UpgradeTotalContrib Callable to upgrade TotalContribmutable field to new implementation.
⚠️ Note: Only the dex owner can invoke this transition
UpgradeXTotalContrib Callable to upgrade xtotalContribmutable field to new implementation.
⚠️ Note: Only the dex owner can invoke this transition
TransferZils Transfers the ZIL balance from old implementation to new implementation.
⚠️ Note: Only the dex owner can invoke this transition.
TransferTokens Transfers tokens from old implementation to new implementation in pools.
⚠️ Note: Only the dex owner can invoke this transition
TransferTreasuryTokens Transfers tokens from old implementation to new implementation in treasury_balances.
⚠️ Note: Only the dex owner can invoke this transition
TransferXTokens Transfers tokens from old implementation to new implementation in xpools.
⚠️ Note: Only the dex owner can invoke this transition.
UpgradeTo Change the current implementation address of the DEX_Xcad contract.
⚠️ Note: Only the proxy admin can invoke this transition

Callback Transitions

Name Description
TransferFromSuccessCallBack Callable to dex contract when it sends token by invoking TransferFrom transition in Fungible Token contract.
TransferSuccessCallBack Callable to dex contract when it sends token by invoking Transfer transition in Fungible Token contract.
RecipientAcceptTransferFrom Callable to dex contract when it receives token using TransferFrom transition in Fungible Token contract.
RecipientAcceptTransfer Callable to dex contract when it receives token using Transfer transition in Fungible Token contract.
AddFunds Callable to dex contract when it receives ZIL.

Errors

RequestedRatesCannotBeFulfilled

The prevailing exchange rate determined by the constant product formula of the liquidity pool reserves is too unfavourable for the given transition parameters. Ensure that the given parameters are correct, and that enough buffer (slippage allowance) is given to prevent unneccessary reverts. Using amounts that are bounded to be exactly the exchange rate at submission time is unlikely to succeed.

TransactionExpired

The transaction took too long to confirm and exceeded the given deadline_block parameter. Retry the transition with a later deadline_block.

ReceiveFailed

A transfer of ZRC-2 tokens to the Zilswap smart contract failed. Ensure that the sender has approved a sufficient amount of token transfers via IncreaseAllowance.

InvalidParameter

A parameter is invalid, most likely due to being zero 0. Ensure that all transition parameters are valid.

MissingPool

The pool does not exist for swapping of tokens. Liquidity needs to be added through AddLiquidity first.

MissingBalance

The pool balance does not exist for tokens.

MissingContributions

No contributions found for pool token.

IntegerOverflow

The pool size is too large. Retry with smaller amounts.

ExistingOwner

Address passed for TransferOwnership is current owner.

InvalidSender

User is not allowed to accept pending ownership.

InvalidFee

Fee passed for SetFee is not valid.

InvalidToken0LiquidityParameter

Token0 amount is less than min liquidity required.

InvalidToken1LiquidityParameter

Token1 amount is less than min liquidity required.

InvalidTokenOrderForAddLiquidity

Token order for Adding Liquidity is invalid.

InvalidTokenOrderForRemoveLiquidity

Token order for Remove Liquidity is invalid.

InvalidParameterMinZil

Zil amount is less than 1000 zils.

InvalidInvocation

A user cannot transfer amount to self.

Modified ZRC-2

Official ZRC-2 reference contact and spec can be found here. To meet the requirements of batch token transfer and DEX whitelisting, reference ZRC-2 contract has been modified.

New Mutable Fields added

Name Description
dex_check_enabled It stores the current state of dex check value(True/False). True value indicates that dex is enabled.
dexs It stores the addresses of DEX and corresponding True/False values which indicates whether DEX is enabled or disabled.
pending_owner It stores the address of new proposed owner after current_owner invokes TransferOwnership transition.

New Procedures added

Name Description
ThrowIfDexNotFound It throws exception if dex address is not found
ThrowIfDexIsActive It throws exception if dex is active
ThrowIfDexIsInActive It throws exception if dex is inactive

Modified Transitions

Name Description
IncreaseAllowance IncreaseAllowance is modified to check for active state of DEX
DecreaseAllowance DecreaseAllowance is modified to check for active state of DEX

New Transitions Added

Name Description
BatchTransfer BatchTransfer is added to support token transfer in batch. It accepts List of pair of address and token amount.
EnableDexCheck EnableDexCheck transition enables Dex whitelisting check.
⚠️ Note: Only the current_owner can invoke this transition.
DisableDexCheck DisableDexCheck disables Dex whitelisting check.
⚠️ Note: Only the current_owner can invoke this transition.
AddDex AddDex adds a new dex for whitelisting. Default status is True, dex is whitelisted.
⚠️ Note: Only the current_owner can invoke this transition.
DisableDex DisableDex disables dex. Status is set to False, dex is not allowed to trade token.
⚠️ Note: Only the current_owner can invoke this transition.
RemoveDex RemoveDex removes dex address entry from contract. Dex is not allowed to trade token.
⚠️ Note: Only the current_owner can invoke this transition.
TransferOwnership TransferOwnership adds pending_owner. So that a new owner can claim and become owner of contract.
⚠️ Note: Only the current_owner can invoke this transition.
AcceptPendingOwnership Upon invocation of this transtion pending_owner becomes the current owner of contract.

Modified ZRC-2-V2

Official ZRC-2 reference contact and spec can be found here. This version of the smart contract is an extension on the modified ZRC 2 contract menntioned above. This is to make the contract Mintable, Burnable and Capped.

New ImMutable Fields added

Name Description
cap This is the maximum number of tokens that can be minted.

New Mutable Fields added

Name Description
minters It stores the addresses users or smart contracts of DEX and corresponding True/False values which indicates whether the address is a Minter i.e. can Mint new tokens.

New Procedures added

Name Description
AuthorizedMint It Mint new tokens if the amount to be minted does not make it exceed the Cap. It throws exception if excced Cap
AuthorizedBurnIfSufficientBalance It burns existing tokens from users balance. It throws exception if user does not have enough in balance
IsMinter It throws exception if the account given is not a Minter

Modified Transitions

Name Description

New Transitions Added

Name Description
Mint Mint new tokens to the recipient account. It throws exception if the caller is not a Minter or if the Cap is exceeded
Burn Burn the tokens. It can be calleed by any user to burns its own balance. It throws exception if the user does not have enough tokens
SetMinter Add a new account to the Minters list. Default status is the contract owner, others Minters can be added with this transition.
⚠️ Note: Only the current_owner can invoke this transition.
RemoveMinter Removes an account from the Minters list.
⚠️ Note: Only the current_owner can invoke this transition.

Modified ZRC-2-V3

Official ZRC-2 reference contact and spec can be found here. This version of the smart contract is an extension on the modified ZRC 2 V2 contract menntioned above. This is to make the contract support Sell On Fee.

New Mutable Fields added

Name Description
sell_fee_bps It stores the current sell on fee rate. The value is in bps. 1 bps = 0.01%. Default valueis 500bps = 5%. The fee can be set to 0 to effectively turn off sell fee.
sell_fee_recipient It stores the address ofthe account that will receive sellon fees. Default is contract_owner

New Procedures added

Name Description
RequireValidSellFee It throws exception if the fee given is out ot range. The range is 0 and 10000
RequireValidDestination It throws exception if the address is zero or same as this contract.

Modified Transitions

Name Description

New Transitions Added

Name Description
SetSellFeeBPS Set the new sell on fee. The valid range is 0 - 10000. It throws exception if not called by contrat Owner or fee is out of range.
⚠️ Note: Only the current_owner can invoke this transition.
SetSellFeeRecipient Set the new account to receive sell on fees. It throws exception if new recipient is zero address or same as this contract
⚠️ Note: Only the current_owner can invoke this transition.

Environment

Ceres is a graphical user interface that runs different Zilliqa development tools under Docker container. Ceres will take care of Zilliqa tools for scilla contact development. System requirements and installation instructions can be found here.

Test

Document related to tests can be found here

DEX Upgrade

Document related to upgrade can be found here

Zilswap Issue

It was found that Zilswap contract had a major bug. It was missing check for user's contribution in LP and it could potentially drain the pools.

Below code snippet is taken from zilswap contract

transition RemoveLiquidity(
  token_address : ByStr20,
  contribution_amount : Uint128,
  min_zil_amount : Uint128,
  min_token_amount : Uint128,
  deadline_block : BNum
)
  ThrowIfExpired deadline_block;
  ThrowIfZero contribution_amount;
  ThrowIfZero min_zil_amount;
  ThrowIfZero min_token_amount;

  token = Token token_address;

  maybe_total_contribution <- total_contributions[token_address];
  match maybe_total_contribution with
  | None =>
    e = { _exception : "MissingPool" };
    throw e
  | Some total_contribution =>
    ThrowIfZero total_contribution;
    maybe_pool <- pools[token_address];
    match maybe_pool with
    | None =>
      e = { _exception : "MissingPool" };
      throw e
    | Some pool =>
      match pool with
      | Pool x y => (* zil reserve, token reserve *)
        maybe_zil_amount = frac contribution_amount total_contribution x;
        maybe_token_amount = frac contribution_amount total_contribution y;
        match maybe_zil_amount with
        | None =>
          e = { _exception : "IntegerOverflow" };
          throw e
        | Some zil_amount =>
          match maybe_token_amount with
          | None =>
            e = { _exception : "IntegerOverflow" };
            throw e
          | Some token_amount =>
            within_limits =
              let zil_ok = uint128_ge zil_amount min_zil_amount in
              let token_ok = uint128_ge token_amount min_token_amount in
              andb zil_ok token_ok;
            match within_limits with
            | False =>
              e = { _exception : "RequestedRatesCannotBeFulfilled" };
              throw e
            | True =>
              existing_balance <- balances[token_address][_sender];
              match existing_balance with
              | None =>
                e = { _exception : "MissingBalance" };
                throw e
              | Some b =>
                new_pool =
                  let new_x = builtin sub x zil_amount in
                  let new_y = builtin sub y token_amount in
                  Pool new_x new_y;

                is_pool_now_empty = poolEmpty new_pool;
                match is_pool_now_empty with
                | True =>
                  (* clear pool entries when there is no more liquidity *)
                  delete pools[token_address];
                  delete balances[token_address];
                  delete total_contributions[token_address]
                | False =>
                  pools[token_address] := new_pool;
                  new_balance = builtin sub b contribution_amount;
                  balances[token_address][_sender] := new_balance;
                  new_total_contribution = builtin sub total_contribution contribution_amount;
                  total_contributions[token_address] := new_total_contribution
                end;

                zils_out = Coins zil zil_amount;
                tokens_out = Coins token token_amount;
                Send zils_out _sender;
                Send tokens_out _sender;

                e = { _eventname: "Burnt"; pool: token_address; address: _sender; amount: contribution_amount };
                event e
              end
            end
          end
        end
      end
    end
  end
end

In the above transition refer to the section,

new_pool =
    let new_x = builtin sub x zil_amount in
    let new_y = builtin sub y token_amount in
    Pool new_x new_y;

is_pool_now_empty = poolEmpty new_pool;
match is_pool_now_empty with
| True =>
    (* clear pool entries when there is no more liquidity *)
    delete pools[token_address];
    delete balances[token_address];
    delete total_contributions[token_address]
| False =>
    pools[token_address] := new_pool;
    new_balance = builtin sub b contribution_amount;
    balances[token_address][_sender] := new_balance;
    new_total_contribution = builtin sub total_contribution contribution_amount;
    total_contributions[token_address] := new_total_contribution
end;

It is missing check for contribution_amount. User can provide the contribution_amount which could possibly drain the pool and entire pool tokens can be transferred to his wallet.

Fix is to move new_balance and new_total_contribution calculation up so that it would fail default with exception if user's contribution amount exceeds his balance.

new_balance = builtin sub b contribution_amount;
new_total_contribution = builtin sub total_contribution contribution_amount;
new_pool =
    let new_x = builtin sub x zil_amount in
    let new_y = builtin sub y token_amount in
    Pool new_x new_y;

is_pool_now_empty = poolEmpty new_pool;
match is_pool_now_empty with
| True =>
    (* clear pool entries when there is no more liquidity *)
    delete pools[token_address];
    delete balances[token_address];
    delete total_contributions[token_address]
| False =>
    pools[token_address] := new_pool;
    balances[token_address][_sender] := new_balance;
    total_contributions[token_address] := new_total_contribution
end;

This fix has been applied for remove liquidity in zil<>zrc2 as well as zrc2<>zrc2 pools.

About

Router for XCAD tokens coded in Scilla for Zilliqa Blockchain

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published