Direct Trades
(Single Swaps)
Direct trades between base currency and share tokens is most simple way trade share tokens. Especially for aggregators it is recommended to implement these trades.
The following examples shows you how to implement a trade contract, you will implement two functions:
buySharesDirectsellSharesDirect
The buySharesDirect function performs an exact output swap, which swaps a minimum possible amount of base currency token for a fixed amount of share token. This function uses the ExactOutputSingleParams struct and the exactOutputSingle function from the ISwapRouter interface.
The sellSharesDirect function an exact input swap, which swaps a fixed amount of share tokens for maximum possible amount of base currency tokens. This function uses the ExactInputSingleParams struct and the exactInputSingle function from the ISwapRouter interface.
For simplification, the example hardcodes the token contract addresses, but as explained further below the contract could be modified to change pools and tokens on a per transaction basis.
When trading from a smart contract, the most important thing to keep in mind is that access to an external price source is required. Without this, trades can be frontrun for considerable loss.
Note: The swap examples are not production ready code, and are implemented in a simplistic manner for the purpose of learning.
Set Up the Contract
Declare the solidity version used to compile the contract.
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.8.21;Import two relevant contracts from the Uniswap npm package
import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol';
import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';Create a contract called TradeExamples, and declare an immutable public variable swapRouter of type ISwapRouter. This allows us to call functions in the ISwapRouter interface.
Hardcode the base currency and share token contract addresses for the example. In production, you would likely use an input parameter for this and pass the input into a memory variable, allowing the contract to change the brokerbot and tokens it interacts with on a per transaction basis, but for conceptual simplicity, we are hardcoding them here.
Buy Shares
The caller must approve the contract to withdraw the base currency tokens from the calling address's account to execute a trade. Remember that because our contract is a contract itself and not an extension of the caller (us); we must also approve the Brokerbot router contract to use the tokens that our contract will be in possession of after they have been withdrawn from the calling address (us).
Then, transfer the amount of XCHF from the calling address into our contract, and use amount as the value passed to the second approve.
Input Parameters
To execute the swap function, we need to populate the ExactOutputSingleParams with the necessary swap data. These parameters are found in the smart contract interfaces, which can be browsed here.
A brief overview of the parameters:
tokenInThe contract address of base currency tokentokenOutThe contract address of the share tokenfeeWe set this to zero - as the brokerbot router doesn't use itrecipientthe destination address of the shares tokendeadline: the unix time after which a swap will fail, to protect against long-pending transactions and wild swings in pricesamountOutMinimum: For a real deployment, this value should be calculated using the brokerbot quoter - this helps protect against getting an unusually bad price for a trade due to a front running sandwich or another type of price manipulationsqrtPriceLimitX96: We set this to zero - as the brokerbot router doesn't use it
Call the Function
Pay back overspend
Because this example transfers in the inbound asset in anticipation of the trade - its possible that some of the inbound token will be left over after the trade is executed, which is why we pay it back to the calling address at the end of the trade.
Selling Shares
The caller must approve the contract to withdraw the share tokens from the calling address's account to execute a trade. Remember that because our contract is a contract itself and not an extension of the caller (us); we must also approve the brokerbot router contract to use the tokens that our contract will be in possession of after they have been withdrawn from the calling address (us).
Then, transfer the amount of shares from the calling address into our contract, and use amount as the value passed to the second approve.
Input Parameters
To execute the swap function, we need to populate the ExactInputSingleParams with the necessary swap data. These parameters are found in the smart contract interfaces, which can be browsed here.
A brief overview of the parameters:
tokenInThe contract address of the inbound tokentokenOutThe contract address of the outbound tokenfeeThe fee tier of the pool, used to determine the correct pool contract in which to execute the swaprecipientthe destination address of the outbound tokendeadline: the unix time after which a swap will fail, to protect against long-pending transactions and wild swings in pricesamountOutMinimum: we are setting to zero, but this is a significant risk in production. For a real deployment, this value should be calculated using our SDK or an onchain price oracle - this helps protect against getting an unusually bad price for a trade due to a front running sandwich or another type of price manipulationsqrtPriceLimitX96: We set this to zero - which makes this parameter inactive. In production, this value can be used to set the limit for the price the swap will push the pool to, which can help protect against price impact or for setting up logic in a variety of price-relevant mechanisms.
Call the function
A Complete Trading Contract
Last updated
Was this helpful?