The two most curcial input values when using the CurveRouter are _route, which determines the route of the exchange and _swap_params, which includes swap parameters such as input and output token, swap type, pool type and number of coins in the pool.
The route input is an array of up to 11 addresses. When calling the function, the array must always include 11 addresses. Unused spots in the array need to be filled with ZERO_ADDRESS. The route consists of tokens and pools or zaps. The first address is always the input token, the last one always the output token. The addresses inbetween compose the route the user wants to trade.
The example demonstrates a swap of wETH for crvUSD. The process involves two stages. First, wETH is swapped for USDC using the tricryptoUSDC pool. Subsequently, USDC is exchanged for crvUSD using the crvUSD/USDC pool.
Swap parameters are defined in a multidimensional array which provides essential information about which tokens to swap using a specified pool.
The array structure includes the following elements: [i, j, swap_type, pool_type, n_coins]. The first array of this multidimensional setup corresponds to the initial token exchange in the swap sequence.
i: Index of the input token, fetched from pool.coins('token address').
j: Index of the output token, fetched from pool.coins('token address').
swap_type
Description
1
Standard token exchange
2
Underlying token exchange_underlying
3
Underlying exchange via zap for factory stable metapools and crypto-meta pools (exchange_underlying for stable, exchange in zap for crypto)
4
Coin to LP token "exchange" (effectively add_liquidity)
5
Lending pool underlying coin to LP token "exchange" (effectively add_liquidity)
6
LP token to coin "exchange" (effectively remove_liquidity_one_coin)
7
LP token to lending or fake pool underlying coin "exchange" (effectively remove_liquidity_one_coin)
8
Specialized swaps like ETH <-> WETH, ETH -> stETH or frxETH, and cross-liquidity between staked tokens (e.g., stETH <-> wstETH, frxETH <-> sfrxETH)
9
SNX-related swaps (e.g., sUSD, sEUR, sETH, sBTC)
pool_type
Description
1
Stable pools using the Stableswap algorithm
2
Two-coin Crypto pools using the Cryptoswap algorithm
3
Tricrypto pools with three coins using the Cryptoswap algorithm
4
Llamma pools, typically used in crvUSD and lending markets
n_coins: Number of coins contained within the pool.
[[2,0,1,3,3],# first swap: wETH -> USDC using tricryptoUSDC pool[0,1,1,1,2],# second swap: USDC -> crvUSD using crvUSD/USDC pool[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],]
Let's take a closer look at the first array, which represents the swap parameters for the first exchange (wETH -> USDC). i = 2 because the coin index value of wETH in the tricryptoUSDC pool is 2. This can be obtained by calling tricryptoUSDC.coins(n). Similarly, j = 0 because USDC has the coin index value of 0. The swap type is a regular exchange, represented by 0. The pool_type is 3, as it is a tricrypto pool (a cryptoswap algorithm consisting of three coins: USDC, wBTC, and wETH). The last value in the array represents the number of coins in the pool, which is 3.
The values of the second array should be set according to the crvUSD/USDC pool.
The router has a single exchange function, which allows up to 5 swaps in a single transaction.
Routing and swap parameters need to be determined off-chain. The exchange functionality of the router is designed for gas efficiency over ease-of-use. An accompanying JavaScript library can be found on GitHub, which is used in the Curve UI to determine route and swap parameters.
The amount of the input token (_route[0]) to be sent.
_expected
uint256
The minimum amount received after the final swap.
_pools
address[5]
Array of pools for swaps via zap contracts. This parameter is only needed for swap_type = 3.
receiver
address
Address to transfer the final output token to. Defaults to msg.sender.
Source code
eventExchange:sender:indexed(address)receiver:indexed(address)route:address[11]swap_params:uint256[5][5]pools:address[5]in_amount:uint256out_amount:uint256ETH_ADDRESS:constant(address)=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeESTETH_ADDRESS:constant(address)=0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84WSTETH_ADDRESS:constant(address)=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0FRXETH_ADDRESS:constant(address)=0x5E8422345238F34275888049021821E8E08CAa1fSFRXETH_ADDRESS:constant(address)=0xac3E018457B222d93114458476f3E3416Abbe38FWBETH_ADDRESS:constant(address)=0xa2E3356610840701BDf5611a53974510Ae27E2e1WETH_ADDRESS:immutable(address)# SNX# https://github.com/Synthetixio/synthetix-docs/blob/master/content/addresses.mdSNX_ADDRESS_RESOLVER:constant(address)=0x823bE81bbF96BEc0e25CA13170F5AaCb5B79ba83SNX_TRACKING_CODE:constant(bytes32)=0x4355525645000000000000000000000000000000000000000000000000000000# CURVESNX_EXCHANGER_NAME:constant(bytes32)=0x45786368616E6765720000000000000000000000000000000000000000000000# Exchangersnx_currency_keys:HashMap[address,bytes32]@external@payable@nonreentrant('lock')defexchange(_route:address[11],_swap_params:uint256[5][5],_amount:uint256,_expected:uint256,_pools:address[5]=empty(address[5]),_receiver:address=msg.sender)->uint256:""" @notice Performs up to 5 swaps in a single transaction. @dev Routing and swap params must be determined off-chain. This functionality is designed for gas efficiency over ease-of-use. @param _route Array of [initial token, pool or zap, token, pool or zap, token, ...] The array is iterated until a pool address of 0x00, then the last given token is transferred to `_receiver` @param _swap_params Multidimensional array of [i, j, swap type, pool_type, n_coins] where i is the index of input token j is the index of output token The swap_type should be: 1. for `exchange`, 2. for `exchange_underlying`, 3. for underlying exchange via zap: factory stable metapools with lending base pool `exchange_underlying` and factory crypto-meta pools underlying exchange (`exchange` method in zap) 4. for coin -> LP token "exchange" (actually `add_liquidity`), 5. for lending pool underlying coin -> LP token "exchange" (actually `add_liquidity`), 6. for LP token -> coin "exchange" (actually `remove_liquidity_one_coin`) 7. for LP token -> lending or fake pool underlying coin "exchange" (actually `remove_liquidity_one_coin`) 8. for ETH <-> WETH, ETH -> stETH or ETH -> frxETH, stETH <-> wstETH, frxETH <-> sfrxETH, ETH -> wBETH 9. for SNX swaps (sUSD, sEUR, sETH, sBTC) pool_type: 1 - stable, 2 - crypto, 3 - tricrypto, 4 - llamma n_coins is the number of coins in pool @param _amount The amount of input token (`_route[0]`) to be sent. @param _expected The minimum amount received after the final swap. @param _pools Array of pools for swaps via zap contracts. This parameter is only needed for swap_type = 3. @param _receiver Address to transfer the final output token to. @return Received amount of the final output token. """input_token:address=_route[0]output_token:address=empty(address)amount:uint256=_amount# validate / transfer initial tokenifinput_token==ETH_ADDRESS:assertmsg.value==amountelse:assertmsg.value==0assertERC20(input_token).transferFrom(msg.sender,self,amount,default_return_value=True)foriinrange(1,6):# 5 rounds of iteration to perform up to 5 swapsswap:address=_route[i*2-1]pool:address=_pools[i-1]# Only for Polygon meta-factories underlying swap (swap_type == 6)output_token=_route[i*2]params:uint256[5]=_swap_params[i-1]# i, j, swap_type, pool_type, n_coinsifnotself.is_approved[input_token][swap]:assertERC20(input_token).approve(swap,max_value(uint256),default_return_value=True,skip_contract_check=True)self.is_approved[input_token][swap]=Trueeth_amount:uint256=0ifinput_token==ETH_ADDRESS:eth_amount=amount# perform the swap according to the swap typeifparams[2]==1:ifparams[3]==1:# stableStablePool(swap).exchange(convert(params[0],int128),convert(params[1],int128),amount,0,value=eth_amount)else:# crypto, tricrypto or llammaifinput_token==ETH_ADDRESSoroutput_token==ETH_ADDRESS:CryptoPoolETH(swap).exchange(params[0],params[1],amount,0,True,value=eth_amount)else:CryptoPool(swap).exchange(params[0],params[1],amount,0)elifparams[2]==2:ifparams[3]==1:# stableStablePool(swap).exchange_underlying(convert(params[0],int128),convert(params[1],int128),amount,0,value=eth_amount)else:# crypto or tricryptoCryptoPool(swap).exchange_underlying(params[0],params[1],amount,0,value=eth_amount)elifparams[2]==3:# SWAP IS ZAP HERE !!!ifparams[3]==1:# stableLendingBasePoolMetaZap(swap).exchange_underlying(pool,convert(params[0],int128),convert(params[1],int128),amount,0)else:# crypto or tricryptouse_eth:bool=input_token==ETH_ADDRESSoroutput_token==ETH_ADDRESSCryptoMetaZap(swap).exchange(pool,params[0],params[1],amount,0,use_eth,value=eth_amount)elifparams[2]==4:ifparams[4]==2:amounts:uint256[2]=[0,0]amounts[params[0]]=amountStablePool2Coins(swap).add_liquidity(amounts,0,value=eth_amount)elifparams[4]==3:amounts:uint256[3]=[0,0,0]amounts[params[0]]=amountStablePool3Coins(swap).add_liquidity(amounts,0,value=eth_amount)elifparams[4]==4:amounts:uint256[4]=[0,0,0,0]amounts[params[0]]=amountStablePool4Coins(swap).add_liquidity(amounts,0,value=eth_amount)elifparams[4]==5:amounts:uint256[5]=[0,0,0,0,0]amounts[params[0]]=amountStablePool5Coins(swap).add_liquidity(amounts,0,value=eth_amount)elifparams[2]==5:amounts:uint256[3]=[0,0,0]amounts[params[0]]=amountLendingStablePool3Coins(swap).add_liquidity(amounts,0,True,value=eth_amount)# example: aave on Polygonelifparams[2]==6:ifparams[3]==1:# stableStablePool(swap).remove_liquidity_one_coin(amount,convert(params[1],int128),0)else:# crypto or tricryptoCryptoPool(swap).remove_liquidity_one_coin(amount,params[1],0)# example: atricrypto3 on Polygonelifparams[2]==7:LendingStablePool3Coins(swap).remove_liquidity_one_coin(amount,convert(params[1],int128),0,True)# example: aave on Polygonelifparams[2]==8:ifinput_token==ETH_ADDRESSandoutput_token==WETH_ADDRESS:WETH(swap).deposit(value=amount)elifinput_token==WETH_ADDRESSandoutput_token==ETH_ADDRESS:WETH(swap).withdraw(amount)elifinput_token==ETH_ADDRESSandoutput_token==STETH_ADDRESS:stETH(swap).submit(0x0000000000000000000000000000000000000000,value=amount)elifinput_token==ETH_ADDRESSandoutput_token==FRXETH_ADDRESS:frxETHMinter(swap).submit(value=amount)elifinput_token==STETH_ADDRESSandoutput_token==WSTETH_ADDRESS:wstETH(swap).wrap(amount)elifinput_token==WSTETH_ADDRESSandoutput_token==STETH_ADDRESS:wstETH(swap).unwrap(amount)elifinput_token==FRXETH_ADDRESSandoutput_token==SFRXETH_ADDRESS:sfrxETH(swap).deposit(amount,self)elifinput_token==SFRXETH_ADDRESSandoutput_token==FRXETH_ADDRESS:sfrxETH(swap).redeem(amount,self,self)elifinput_token==ETH_ADDRESSandoutput_token==WBETH_ADDRESS:wBETH(swap).deposit(0xeCb456EA5365865EbAb8a2661B0c503410e9B347,value=amount)else:raise"Swap type 8 is only for ETH <-> WETH, ETH -> stETH or ETH -> frxETH, stETH <-> wstETH, frxETH <-> sfrxETH, ETH -> wBETH"elifparams[2]==9:Synthetix(swap).exchangeAtomically(self.snx_currency_keys[input_token],amount,self.snx_currency_keys[output_token],SNX_TRACKING_CODE,0)else:raise"Bad swap type"# update the amount receivedifoutput_token==ETH_ADDRESS:amount=self.balanceelse:amount=ERC20(output_token).balanceOf(self)# sanity check, if the routing data is incorrect we will have a 0 balance and that is badassertamount!=0,"Received nothing"# check if this was the last swapifi==5or_route[i*2+1]==empty(address):break# if there is another swap, the output token becomes the input for the next roundinput_token=output_tokenamount-=1# Change non-zero -> non-zero costs less gas than zero -> non-zeroassertamount>=_expected,"Slippage"# transfer the final token to the receiverifoutput_token==ETH_ADDRESS:raw_call(_receiver,b"",value=amount)else:assertERC20(output_token).transfer(_receiver,amount,default_return_value=True)logExchange(msg.sender,_receiver,_route,_swap_params,_pools,_amount,amount)returnamount
Array of pools for swaps via zap contracts. This parameter defaults to an empty array and is only needed for swap_type = 3.
Source code
eventExchange:sender:indexed(address)receiver:indexed(address)route:address[11]swap_params:uint256[5][5]pools:address[5]in_amount:uint256out_amount:uint256ETH_ADDRESS:constant(address)=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeESTETH_ADDRESS:constant(address)=0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84WSTETH_ADDRESS:constant(address)=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0FRXETH_ADDRESS:constant(address)=0x5E8422345238F34275888049021821E8E08CAa1fSFRXETH_ADDRESS:constant(address)=0xac3E018457B222d93114458476f3E3416Abbe38FWBETH_ADDRESS:constant(address)=0xa2E3356610840701BDf5611a53974510Ae27E2e1WETH_ADDRESS:immutable(address)# SNX# https://github.com/Synthetixio/synthetix-docs/blob/master/content/addresses.mdSNX_ADDRESS_RESOLVER:constant(address)=0x823bE81bbF96BEc0e25CA13170F5AaCb5B79ba83SNX_TRACKING_CODE:constant(bytes32)=0x4355525645000000000000000000000000000000000000000000000000000000# CURVESNX_EXCHANGER_NAME:constant(bytes32)=0x45786368616E6765720000000000000000000000000000000000000000000000# Exchangersnx_currency_keys:HashMap[address,bytes32]@view@externaldefget_dy(_route:address[11],_swap_params:uint256[5][5],_amount:uint256,_pools:address[5]=empty(address[5]))->uint256:""" @notice Get amount of the final output token received in an exchange @dev Routing and swap params must be determined off-chain. This functionality is designed for gas efficiency over ease-of-use. @param _route Array of [initial token, pool or zap, token, pool or zap, token, ...] The array is iterated until a pool address of 0x00, then the last given token is transferred to `_receiver` @param _swap_params Multidimensional array of [i, j, swap type, pool_type, n_coins] where i is the index of input token j is the index of output token The swap_type should be: 1. for `exchange`, 2. for `exchange_underlying`, 3. for underlying exchange via zap: factory stable metapools with lending base pool `exchange_underlying` and factory crypto-meta pools underlying exchange (`exchange` method in zap) 4. for coin -> LP token "exchange" (actually `add_liquidity`), 5. for lending pool underlying coin -> LP token "exchange" (actually `add_liquidity`), 6. for LP token -> coin "exchange" (actually `remove_liquidity_one_coin`) 7. for LP token -> lending or fake pool underlying coin "exchange" (actually `remove_liquidity_one_coin`) 8. for ETH <-> WETH, ETH -> stETH or ETH -> frxETH, stETH <-> wstETH, frxETH <-> sfrxETH, ETH -> wBETH 9. for SNX swaps (sUSD, sEUR, sETH, sBTC) pool_type: 1 - stable, 2 - crypto, 3 - tricrypto, 4 - llamma n_coins is the number of coins in pool @param _amount The amount of input token (`_route[0]`) to be sent. @param _pools Array of pools for swaps via zap contracts. This parameter is needed only for swap_type = 3. @return Expected amount of the final output token. """input_token:address=_route[0]output_token:address=empty(address)amount:uint256=_amountforiinrange(1,6):# 5 rounds of iteration to perform up to 5 swapsswap:address=_route[i*2-1]pool:address=_pools[i-1]# Only for Polygon meta-factories underlying swap (swap_type == 4)output_token=_route[i*2]params:uint256[5]=_swap_params[i-1]# i, j, swap_type, pool_type, n_coins# Calc output amount according to the swap typeifparams[2]==1:ifparams[3]==1:# stableamount=StablePool(swap).get_dy(convert(params[0],int128),convert(params[1],int128),amount)else:# crypto or llammaamount=CryptoPool(swap).get_dy(params[0],params[1],amount)elifparams[2]==2:ifparams[3]==1:# stableamount=StablePool(swap).get_dy_underlying(convert(params[0],int128),convert(params[1],int128),amount)else:# cryptoamount=CryptoPool(swap).get_dy_underlying(params[0],params[1],amount)elifparams[2]==3:# SWAP IS ZAP HERE !!!ifparams[3]==1:# stableamount=StablePool(pool).get_dy_underlying(convert(params[0],int128),convert(params[1],int128),amount)else:# cryptoamount=CryptoMetaZap(swap).get_dy(pool,params[0],params[1],amount)elifparams[2]in[4,5]:ifparams[3]==1:# stableamounts:uint256[10]=[0,0,0,0,0,0,0,0,0,0]amounts[params[0]]=amountamount=STABLE_CALC.calc_token_amount(swap,output_token,amounts,params[4],True,True)else:# Tricrypto pools have stablepool interface for calc_token_amountifparams[4]==2:amounts:uint256[2]=[0,0]amounts[params[0]]=amountifparams[3]==2:# cryptoamount=CryptoPool2Coins(swap).calc_token_amount(amounts)else:# tricryptoamount=StablePool2Coins(swap).calc_token_amount(amounts,True)elifparams[4]==3:amounts:uint256[3]=[0,0,0]amounts[params[0]]=amountifparams[3]==2:# cryptoamount=CryptoPool3Coins(swap).calc_token_amount(amounts)else:# tricryptoamount=StablePool3Coins(swap).calc_token_amount(amounts,True)elifparams[4]==4:amounts:uint256[4]=[0,0,0,0]amounts[params[0]]=amountifparams[3]==2:# cryptoamount=CryptoPool4Coins(swap).calc_token_amount(amounts)else:# tricryptoamount=StablePool4Coins(swap).calc_token_amount(amounts,True)elifparams[4]==5:amounts:uint256[5]=[0,0,0,0,0]amounts[params[0]]=amountifparams[3]==2:# cryptoamount=CryptoPool5Coins(swap).calc_token_amount(amounts)else:# tricryptoamount=StablePool5Coins(swap).calc_token_amount(amounts,True)elifparams[2]in[6,7]:ifparams[3]==1:# stableamount=StablePool(swap).calc_withdraw_one_coin(amount,convert(params[1],int128))else:# cryptoamount=CryptoPool(swap).calc_withdraw_one_coin(amount,params[1])elifparams[2]==8:ifinput_token==WETH_ADDRESSoroutput_token==WETH_ADDRESSor\
(input_token==ETH_ADDRESSandoutput_token==STETH_ADDRESS)or\
(input_token==ETH_ADDRESSandoutput_token==FRXETH_ADDRESS):# ETH <--> WETH rate is 1:1# ETH ---> stETH rate is 1:1# ETH ---> frxETH rate is 1:1passelifinput_token==WSTETH_ADDRESS:amount=wstETH(swap).getStETHByWstETH(amount)elifoutput_token==WSTETH_ADDRESS:amount=wstETH(swap).getWstETHByStETH(amount)elifinput_token==SFRXETH_ADDRESS:amount=sfrxETH(swap).convertToAssets(amount)elifoutput_token==SFRXETH_ADDRESS:amount=sfrxETH(swap).convertToShares(amount)elifoutput_token==WBETH_ADDRESS:amount=amount*10**18/wBETH(swap).exchangeRate()else:raise"Swap type 8 is only for ETH <-> WETH, ETH -> stETH or ETH -> frxETH, stETH <-> wstETH, frxETH <-> sfrxETH, ETH -> wBETH"elifparams[2]==9:snx_exchanger:address=SynthetixAddressResolver(SNX_ADDRESS_RESOLVER).getAddress(SNX_EXCHANGER_NAME)atomic_amount_and_fee:AtomicAmountAndFee=SynthetixExchanger(snx_exchanger).getAmountsForAtomicExchange(amount,self.snx_currency_keys[input_token],self.snx_currency_keys[output_token])amount=atomic_amount_and_fee.amountReceivedelse:raise"Bad swap type"# check if this was the last swapifi==5or_route[i*2+1]==empty(address):break# if there is another swap, the output token becomes the input for the next roundinput_token=output_tokenreturnamount-1
Array of base pools (for meta pools). Defaults to an empty array.
_base_tokens
address[5]
Array of base LP tokens (for meta pools). Should be a zap address for double meta pools. Defaults to an empty array.
Source code
eventExchange:sender:indexed(address)receiver:indexed(address)route:address[11]swap_params:uint256[5][5]pools:address[5]in_amount:uint256out_amount:uint256ETH_ADDRESS:constant(address)=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeESTETH_ADDRESS:constant(address)=0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84WSTETH_ADDRESS:constant(address)=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0FRXETH_ADDRESS:constant(address)=0x5E8422345238F34275888049021821E8E08CAa1fSFRXETH_ADDRESS:constant(address)=0xac3E018457B222d93114458476f3E3416Abbe38FWBETH_ADDRESS:constant(address)=0xa2E3356610840701BDf5611a53974510Ae27E2e1WETH_ADDRESS:immutable(address)# SNX# https://github.com/Synthetixio/synthetix-docs/blob/master/content/addresses.mdSNX_ADDRESS_RESOLVER:constant(address)=0x823bE81bbF96BEc0e25CA13170F5AaCb5B79ba83SNX_TRACKING_CODE:constant(bytes32)=0x4355525645000000000000000000000000000000000000000000000000000000# CURVESNX_EXCHANGER_NAME:constant(bytes32)=0x45786368616E6765720000000000000000000000000000000000000000000000# Exchangersnx_currency_keys:HashMap[address,bytes32]@view@externaldefget_dx(_route:address[11],_swap_params:uint256[5][5],_out_amount:uint256,_pools:address[5],_base_pools:address[5]=empty(address[5]),_base_tokens:address[5]=empty(address[5]),)->uint256:""" @notice Calculate the input amount required to receive the desired output amount @dev Routing and swap params must be determined off-chain. This functionality is designed for gas efficiency over ease-of-use. @param _route Array of [initial token, pool or zap, token, pool or zap, token, ...] The array is iterated until a pool address of 0x00, then the last given token is transferred to `_receiver` @param _swap_params Multidimensional array of [i, j, swap type, pool_type, n_coins] where i is the index of input token j is the index of output token The swap_type should be: 1. for `exchange`, 2. for `exchange_underlying`, 3. for underlying exchange via zap: factory stable metapools with lending base pool `exchange_underlying` and factory crypto-meta pools underlying exchange (`exchange` method in zap) 4. for coin -> LP token "exchange" (actually `add_liquidity`), 5. for lending pool underlying coin -> LP token "exchange" (actually `add_liquidity`), 6. for LP token -> coin "exchange" (actually `remove_liquidity_one_coin`) 7. for LP token -> lending or fake pool underlying coin "exchange" (actually `remove_liquidity_one_coin`) 8. for ETH <-> WETH, ETH -> stETH or ETH -> frxETH, stETH <-> wstETH, frxETH <-> sfrxETH, ETH -> wBETH 9. for SNX swaps (sUSD, sEUR, sETH, sBTC) pool_type: 1 - stable, 2 - crypto, 3 - tricrypto, 4 - llamma n_coins is the number of coins in pool @param _out_amount The desired amount of output coin to receive. @param _pools Array of pools. @param _base_pools Array of base pools (for meta pools). @param _base_tokens Array of base lp tokens (for meta pools). Should be a zap address for double meta pools. @return Required amount of input token to send. """amount:uint256=_out_amountfor_iinrange(1,6):# 5 rounds of iteration to perform up to 5 swapsi:uint256=6-_iswap:address=_route[i*2-1]ifswap==empty(address):continueinput_token:address=_route[(i-1)*2]output_token:address=_route[i*2]pool:address=_pools[i-1]base_pool:address=_base_pools[i-1]base_token:address=_base_tokens[i-1]params:uint256[5]=_swap_params[i-1]# i, j, swap_type, pool_type, n_coinsn_coins:uint256=params[4]# Calc a required input amount according to the swap typeifparams[2]==1:ifparams[3]==1:# stableifbase_pool==empty(address):# non-metaamount=STABLE_CALC.get_dx(pool,convert(params[0],int128),convert(params[1],int128),amount,n_coins)else:amount=STABLE_CALC.get_dx_meta(pool,convert(params[0],int128),convert(params[1],int128),amount,n_coins,base_pool)elifparams[3]in[2,3]:# crypto or tricryptoamount=CRYPTO_CALC.get_dx(pool,params[0],params[1],amount,n_coins)else:# llammaamount=Llamma(pool).get_dx(params[0],params[1],amount)elifparams[2]in[2,3]:ifparams[3]==1:# stableifbase_pool==empty(address):# non-metaamount=STABLE_CALC.get_dx_underlying(pool,convert(params[0],int128),convert(params[1],int128),amount,n_coins)else:amount=STABLE_CALC.get_dx_meta_underlying(pool,convert(params[0],int128),convert(params[1],int128),amount,n_coins,base_pool,base_token)else:# cryptoamount=CRYPTO_CALC.get_dx_meta_underlying(pool,params[0],params[1],amount,n_coins,base_pool,base_token)elifparams[2]in[4,5]:# This is not correct. Should be something like calc_add_one_coin. But tests say that it's precise enough.ifparams[3]==1:# stableamount=StablePool(swap).calc_withdraw_one_coin(amount,convert(params[0],int128))else:# cryptoamount=CryptoPool(swap).calc_withdraw_one_coin(amount,params[0])elifparams[2]in[6,7]:ifparams[3]==1:# stableamounts:uint256[10]=[0,0,0,0,0,0,0,0,0,0]amounts[params[1]]=amountamount=STABLE_CALC.calc_token_amount(swap,input_token,amounts,n_coins,False,True)else:# Tricrypto pools have stablepool interface for calc_token_amountifn_coins==2:amounts:uint256[2]=[0,0]amounts[params[1]]=amountifparams[3]==2:# cryptoamount=CryptoPool2Coins(swap).calc_token_amount(amounts)# This is not correctelse:# tricryptoamount=StablePool2Coins(swap).calc_token_amount(amounts,False)elifn_coins==3:amounts:uint256[3]=[0,0,0]amounts[params[1]]=amountifparams[3]==2:# cryptoamount=CryptoPool3Coins(swap).calc_token_amount(amounts)# This is not correctelse:# tricryptoamount=StablePool3Coins(swap).calc_token_amount(amounts,False)elifn_coins==4:amounts:uint256[4]=[0,0,0,0]amounts[params[1]]=amountifparams[3]==2:# cryptoamount=CryptoPool4Coins(swap).calc_token_amount(amounts)# This is not correctelse:# tricryptoamount=StablePool4Coins(swap).calc_token_amount(amounts,False)elifn_coins==5:amounts:uint256[5]=[0,0,0,0,0]amounts[params[1]]=amountifparams[3]==2:# cryptoamount=CryptoPool5Coins(swap).calc_token_amount(amounts)# This is not correctelse:# tricryptoamount=StablePool5Coins(swap).calc_token_amount(amounts,False)elifparams[2]==8:ifinput_token==WETH_ADDRESSoroutput_token==WETH_ADDRESSor\
(input_token==ETH_ADDRESSandoutput_token==STETH_ADDRESS)or\
(input_token==ETH_ADDRESSandoutput_token==FRXETH_ADDRESS):# ETH <--> WETH rate is 1:1# ETH ---> stETH rate is 1:1# ETH ---> frxETH rate is 1:1passelifinput_token==WSTETH_ADDRESS:amount=wstETH(swap).getWstETHByStETH(amount)elifoutput_token==WSTETH_ADDRESS:amount=wstETH(swap).getStETHByWstETH(amount)elifinput_token==SFRXETH_ADDRESS:amount=sfrxETH(swap).convertToShares(amount)elifoutput_token==SFRXETH_ADDRESS:amount=sfrxETH(swap).convertToAssets(amount)elifoutput_token==WBETH_ADDRESS:amount=amount*wBETH(swap).exchangeRate()/10**18else:raise"Swap type 8 is only for ETH <-> WETH, ETH -> stETH or ETH -> frxETH, stETH <-> wstETH, frxETH <-> sfrxETH, ETH -> wBETH"elifparams[2]==9:snx_exchanger:address=SynthetixAddressResolver(SNX_ADDRESS_RESOLVER).getAddress(SNX_EXCHANGER_NAME)atomic_amount_and_fee:AtomicAmountAndFee=SynthetixExchanger(snx_exchanger).getAmountsForAtomicExchange(10**18,self.snx_currency_keys[input_token],self.snx_currency_keys[output_token])amount=amount*10**18/atomic_amount_and_fee.amountReceivedelse:raise"Bad swap type"returnamount