github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/test/scripts/uniswap/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "math/big" 7 "strings" 8 "time" 9 10 "github.com/0xPolygon/supernets2-node/encoding" 11 "github.com/0xPolygon/supernets2-node/log" 12 ERC20 "github.com/0xPolygon/supernets2-node/test/contracts/bin/ERC20" 13 WETH "github.com/0xPolygon/supernets2-node/test/contracts/bin/WETH" 14 "github.com/0xPolygon/supernets2-node/test/contracts/bin/uniswap/v2/core/UniswapV2Factory" 15 "github.com/0xPolygon/supernets2-node/test/contracts/bin/uniswap/v2/core/UniswapV2Pair" 16 "github.com/0xPolygon/supernets2-node/test/contracts/bin/uniswap/v2/interface/UniswapInterfaceMulticall" 17 "github.com/0xPolygon/supernets2-node/test/contracts/bin/uniswap/v2/periphery/UniswapV2Router02" 18 "github.com/0xPolygon/supernets2-node/test/operations" 19 "github.com/ethereum/go-ethereum/accounts/abi/bind" 20 "github.com/ethereum/go-ethereum/common" 21 "github.com/ethereum/go-ethereum/core/types" 22 "github.com/ethereum/go-ethereum/crypto" 23 "github.com/ethereum/go-ethereum/ethclient" 24 ) 25 26 const ( 27 // if you want to test using goerli network 28 // replace this by your goerli infura url 29 networkURL = "http://localhost:8123" 30 // replace this by your account private key 31 pk = "0xdfd01798f92667dbf91df722434e8fbe96af0211d4d1b82bbbbc8f1def7a814f" 32 txTimeout = 60 * time.Second 33 ) 34 35 func main() { 36 ctx := context.Background() 37 log.Infof("connecting to %v", networkURL) 38 client, err := ethclient.Dial(networkURL) 39 chkErr(err) 40 log.Infof("connected") 41 chainID, err := client.ChainID(ctx) 42 chkErr(err) 43 log.Infof("chainID: %v", chainID) 44 auth := getAuth(ctx, client, pk) 45 fmt.Println() 46 balance, err := client.BalanceAt(ctx, auth.From, nil) 47 chkErr(err) 48 log.Debugf("ETH Balance for %v: %v", auth.From, balance) 49 // Deploy ERC20 Tokens to be swapped 50 aCoinAddr, aCoin := deployERC20(auth, client, "A COIN", "ACO") 51 fmt.Println() 52 bCoinAddr, bCoin := deployERC20(auth, client, "B COIN", "BCO") 53 fmt.Println() 54 cCoinAddr, cCoin := deployERC20(auth, client, "C COIN", "CCO") 55 fmt.Println() 56 // Deploy wETH Token, it's required by uniswap to swap ETH by tokens 57 log.Debugf("Deploying wEth SC") 58 wEthAddr, tx, wethSC, err := WETH.DeployWETH(auth, client) 59 chkErr(err) 60 err = operations.WaitTxToBeMined(ctx, client, tx, txTimeout) 61 chkErr(err) 62 log.Debugf("wEth SC tx: %v", tx.Hash().Hex()) 63 log.Debugf("wEth SC addr: %v", wEthAddr.Hex()) 64 fmt.Println() 65 // Deploy Uniswap Factory 66 log.Debugf("Deploying Uniswap Factory") 67 factoryAddr, tx, factory, err := UniswapV2Factory.DeployUniswapV2Factory(auth, client, auth.From) 68 chkErr(err) 69 err = operations.WaitTxToBeMined(ctx, client, tx, txTimeout) 70 chkErr(err) 71 log.Debugf("Uniswap Factory SC tx: %v", tx.Hash().Hex()) 72 log.Debugf("Uniswap Factory SC addr: %v", factoryAddr.Hex()) 73 fmt.Println() 74 // Deploy Uniswap Router 75 log.Debugf("Deploying Uniswap Router") 76 routerAddr, tx, router, err := UniswapV2Router02.DeployUniswapV2Router02(auth, client, factoryAddr, wEthAddr) 77 chkErr(err) 78 err = operations.WaitTxToBeMined(ctx, client, tx, txTimeout) 79 chkErr(err) 80 log.Debugf("Uniswap Router SC tx: %v", tx.Hash().Hex()) 81 log.Debugf("Uniswap Router SC addr: %v", routerAddr.Hex()) 82 fmt.Println() 83 // Deploy Uniswap Interface Multicall 84 log.Debugf("Deploying Uniswap Multicall") 85 multicallAddr, tx, _, err := UniswapInterfaceMulticall.DeployUniswapInterfaceMulticall(auth, client) 86 chkErr(err) 87 err = operations.WaitTxToBeMined(ctx, client, tx, txTimeout) 88 chkErr(err) 89 log.Debugf("Uniswap Interface Multicall SC tx: %v", tx.Hash().Hex()) 90 log.Debugf("Uniswap Interface Multicall SC addr: %v", multicallAddr.Hex()) 91 fmt.Println() 92 // Mint balance to tokens 93 log.Debugf("Minting ERC20 Tokens") 94 aMintAmount := "1000000000000000000000" 95 tx = mintERC20(auth, client, aCoin, aMintAmount) 96 log.Debugf("Mint A Coin tx: %v", tx.Hash().Hex()) 97 fmt.Println() 98 bMintAmount := "1000000000000000000000" 99 tx = mintERC20(auth, client, bCoin, bMintAmount) 100 log.Debugf("Mint B Coin tx: %v", tx.Hash().Hex()) 101 fmt.Println() 102 cMintAmount := "1000000000000000000000" 103 tx = mintERC20(auth, client, cCoin, cMintAmount) 104 log.Debugf("Mint C Coin tx: %v", tx.Hash().Hex()) 105 fmt.Println() 106 // wrapping eth 107 wethDepositoAmount := "20000000000000000" 108 log.Debugf("Depositing %v ETH for account %v on token wEth", wethDepositoAmount, auth.From) 109 wAuth := getAuth(ctx, client, pk) 110 wAuth.Value, _ = big.NewInt(0).SetString(wethDepositoAmount, encoding.Base10) 111 tx, err = wethSC.Deposit(auth) 112 chkErr(err) 113 err = operations.WaitTxToBeMined(ctx, client, tx, txTimeout) 114 chkErr(err) 115 value, err := aCoin.BalanceOf(&bind.CallOpts{}, auth.From) 116 chkErr(err) 117 log.Debugf("before allowance aCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 118 value, err = bCoin.BalanceOf(&bind.CallOpts{}, auth.From) 119 chkErr(err) 120 log.Debugf("before allowance bCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 121 value, err = cCoin.BalanceOf(&bind.CallOpts{}, auth.From) 122 chkErr(err) 123 log.Debugf("before allowance cCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 124 // Add allowance 125 approveERC20(auth, client, aCoin, routerAddr, aMintAmount) 126 fmt.Println() 127 approveERC20(auth, client, bCoin, routerAddr, bMintAmount) 128 fmt.Println() 129 approveERC20(auth, client, cCoin, routerAddr, cMintAmount) 130 fmt.Println() 131 approveERC20(auth, client, wethSC, routerAddr, wethDepositoAmount) 132 fmt.Println() 133 const liquidityAmount = "10000000000000000000" 134 value, err = aCoin.BalanceOf(&bind.CallOpts{}, auth.From) 135 chkErr(err) 136 log.Debugf("before adding liquidity A, B aCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 137 value, err = bCoin.BalanceOf(&bind.CallOpts{}, auth.From) 138 chkErr(err) 139 log.Debugf("before adding liquidity A, B bCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 140 value, err = cCoin.BalanceOf(&bind.CallOpts{}, auth.From) 141 chkErr(err) 142 log.Debugf("before adding liquidity A, B cCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 143 // Add liquidity to the pool 144 tx = addLiquidity(auth, client, router, aCoinAddr, bCoinAddr, liquidityAmount) 145 log.Debugf("Add Liquidity to Pair A <-> B tx: %v", tx.Hash().Hex()) 146 fmt.Println() 147 value, err = aCoin.BalanceOf(&bind.CallOpts{}, auth.From) 148 chkErr(err) 149 log.Debugf("before adding liquidity B, C aCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 150 value, err = bCoin.BalanceOf(&bind.CallOpts{}, auth.From) 151 chkErr(err) 152 log.Debugf("before adding liquidity B, C bCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 153 value, err = cCoin.BalanceOf(&bind.CallOpts{}, auth.From) 154 chkErr(err) 155 log.Debugf("before adding liquidity B, C cCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 156 tx = addLiquidity(auth, client, router, bCoinAddr, cCoinAddr, liquidityAmount) 157 log.Debugf("Add Liquidity to Pair B <-> C tx: %v", tx.Hash().Hex()) 158 fmt.Println() 159 // Execute swaps 160 const swapExactAmountInNumber = 1000000000000000000 161 swapExactAmountIn := big.NewInt(swapExactAmountInNumber) 162 value, err = aCoin.BalanceOf(&bind.CallOpts{}, auth.From) 163 chkErr(err) 164 log.Debugf("before first swap aCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 165 value, err = bCoin.BalanceOf(&bind.CallOpts{}, auth.From) 166 chkErr(err) 167 log.Debugf("before first swap bCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 168 value, err = cCoin.BalanceOf(&bind.CallOpts{}, auth.From) 169 chkErr(err) 170 log.Debugf("before first swap cCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 171 log.Debugf("Swaping tokens from A <-> B") 172 swapExactTokensForTokens(auth, client, factory, router, aCoinAddr, bCoinAddr, swapExactAmountIn) 173 fmt.Println() 174 value, err = aCoin.BalanceOf(&bind.CallOpts{}, auth.From) 175 chkErr(err) 176 log.Debugf("after first swap aCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 177 value, err = bCoin.BalanceOf(&bind.CallOpts{}, auth.From) 178 chkErr(err) 179 log.Debugf("after first swap bCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 180 value, err = cCoin.BalanceOf(&bind.CallOpts{}, auth.From) 181 chkErr(err) 182 log.Debugf("after first swap cCoin.balanceOf[%s]: %d", auth.From.Hex(), value) 183 log.Debugf("Swaping tokens from B <-> C") 184 swapExactTokensForTokens(auth, client, factory, router, bCoinAddr, cCoinAddr, swapExactAmountIn) 185 fmt.Println() 186 } 187 func swapExactTokensForTokens(auth *bind.TransactOpts, client *ethclient.Client, 188 factory *UniswapV2Factory.UniswapV2Factory, router *UniswapV2Router02.UniswapV2Router02, 189 tokenA, tokenB common.Address, exactAmountIn *big.Int) { 190 ctx := context.Background() 191 logPrefix := fmt.Sprintf("swapExactTokensForTokens %v <-> %v", tokenA.Hex(), tokenB.Hex()) 192 pairAddr, err := factory.GetPair(nil, tokenA, tokenB) 193 chkErr(err) 194 log.Debug(logPrefix, " pair: ", pairAddr.Hex()) 195 pairSC, err := UniswapV2Pair.NewUniswapV2Pair(pairAddr, client) 196 chkErr(err) 197 pairReserves, err := pairSC.GetReserves(nil) 198 chkErr(err) 199 log.Debug(logPrefix, " reserves 0: ", pairReserves.Reserve0, " 1: ", pairReserves.Reserve1, " Block Timestamp: ", pairReserves.BlockTimestampLast) 200 amountOut, err := router.GetAmountOut(nil, exactAmountIn, pairReserves.Reserve0, pairReserves.Reserve1) 201 chkErr(err) 202 log.Debug(logPrefix, " exactAmountIn: ", exactAmountIn, " amountOut: ", amountOut) 203 tx, err := router.SwapExactTokensForTokens(auth, exactAmountIn, amountOut, []common.Address{tokenA, tokenB}, auth.From, getDeadline()) 204 chkErr(err) 205 log.Debug(logPrefix, " tx: ", tx.Hash().Hex()) 206 err = operations.WaitTxToBeMined(ctx, client, tx, txTimeout) 207 chkErr(err) 208 } 209 func getAuth(ctx context.Context, client *ethclient.Client, pkHex string) *bind.TransactOpts { 210 chainID, err := client.ChainID(ctx) 211 chkErr(err) 212 privateKey, err := crypto.HexToECDSA(strings.TrimPrefix(pkHex, "0x")) 213 chkErr(err) 214 auth, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID) 215 chkErr(err) 216 return auth 217 } 218 func deployERC20(auth *bind.TransactOpts, client *ethclient.Client, name, symbol string) (common.Address, *ERC20.ERC20) { 219 ctx := context.Background() 220 log.Debugf("Deploying ERC20 Token: [%v]%v", symbol, name) 221 addr, tx, instance, err := ERC20.DeployERC20(auth, client, name, symbol) 222 chkErr(err) 223 err = operations.WaitTxToBeMined(ctx, client, tx, txTimeout) 224 chkErr(err) 225 log.Debugf("%v SC tx: %v", name, tx.Hash().Hex()) 226 log.Debugf("%v SC addr: %v", name, addr.Hex()) 227 return addr, instance 228 } 229 func mintERC20(auth *bind.TransactOpts, client *ethclient.Client, erc20sc *ERC20.ERC20, amount string) *types.Transaction { 230 ctx := context.Background() 231 name, err := erc20sc.Name(nil) 232 chkErr(err) 233 log.Debugf("Minting %v tokens for account %v on token %v", amount, auth.From, name) 234 mintAmount, _ := big.NewInt(0).SetString(amount, encoding.Base10) 235 tx, err := erc20sc.Mint(auth, mintAmount) 236 chkErr(err) 237 err = operations.WaitTxToBeMined(ctx, client, tx, txTimeout) 238 chkErr(err) 239 return tx 240 } 241 func approveERC20(auth *bind.TransactOpts, client *ethclient.Client, 242 sc interface { 243 Name(opts *bind.CallOpts) (string, error) 244 Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) 245 }, 246 routerAddr common.Address, 247 amount string) { 248 ctx := context.Background() 249 name, err := sc.Name(nil) 250 chkErr(err) 251 a, _ := big.NewInt(0).SetString(amount, encoding.Base10) 252 log.Debugf("Approving %v tokens to be used by the router for %v on behalf of account %v", a.Text(encoding.Base10), name, auth.From) 253 tx, err := sc.Approve(auth, routerAddr, a) 254 chkErr(err) 255 err = operations.WaitTxToBeMined(ctx, client, tx, txTimeout) 256 chkErr(err) 257 log.Debugf("Approval %v tx: %v", name, tx.Hash().Hex()) 258 } 259 func addLiquidity(auth *bind.TransactOpts, client *ethclient.Client, router *UniswapV2Router02.UniswapV2Router02, tokenA, tokenB common.Address, amount string) *types.Transaction { 260 ctx := context.Background() 261 a, _ := big.NewInt(0).SetString(amount, encoding.Base10) 262 log.Debugf("Adding liquidity(%v) for tokens A: %v, B:%v, Recipient: %v", amount, tokenA.Hex(), tokenB.Hex(), auth.From.Hex()) 263 tx, err := router.AddLiquidity(auth, tokenA, tokenB, a, a, a, a, auth.From, getDeadline()) 264 chkErr(err) 265 err = operations.WaitTxToBeMined(ctx, client, tx, txTimeout) 266 chkErr(err) 267 return tx 268 } 269 func getDeadline() *big.Int { 270 const deadLinelimit = 5 * time.Minute 271 return big.NewInt(time.Now().UTC().Add(deadLinelimit).Unix()) 272 } 273 func chkErr(err error) { 274 if err != nil { 275 log.Fatal(err) 276 } 277 }