stargate
Mike112
typescript
a year ago
19 kB
4
Indexable
Never
import { ethers } from 'ethers'; const BlockchainData = { "Ethereum": { chainID: 101, rpcProvider: 'https://eth.llamarpc.com', stargateRouter: "0x8731d54E9D02c286767d56ac03e8037C07e01e98", routerETH: "0x150f94B44927F078737562f0fcF3C95c01Cc2376"}, "BnbChain": { chainID: 102, rpcProvider: 'https://bsc-dataseed.binance.org', stargateRouter: "0x4a364f8c717cAAD9A442737Eb7b8A55cc6cf18D8", routerETH: ""}, "Avalanche": { chainID: 106, rpcProvider: 'https://avalanche.public-rpc.com', stargateRouter: "0x45A01E4e04F14f7A4a6702c74187c5F6222033cd", routerETH: ""}, "Polygon": { chainID: 109, rpcProvider: 'https://polygon-rpc.com/', stargateRouter: "0x45A01E4e04F14f7A4a6702c74187c5F6222033cd", routerETH: ""}, "Arbitrum": { chainID: 110, rpcProvider: 'https://arbitrum-one.public.blastapi.io', stargateRouter: "0x53Bf833A5d6c4ddA888F69c22C88C9f356a41614", routerETH: "0xbf22f0f184bCcbeA268dF387a49fF5238dD23E40"}, "Optimism": { chainID: 111, rpcProvider: 'https://mainnet.optimism.io', stargateRouter: "0xB0D502E938ed5f4df2E681fE6E419ff29631d62b", routerETH: "0xB49c4e680174E331CB0A7fF3Ab58afC9738d5F8b"}, "Fantom": { chainID: 112, rpcProvider: 'https://rpc.ftm.tools', stargateRouter: "0xAf5191B0De278C7286d6C7CC6ab6BB8A73bA2Cd6", routerETH: ""}, "Metis": { chainID: 151, rpcProvider: 'https://andromeda.metis.io/?owner=1088', stargateRouter: "0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590", routerETH: ""}, "Base": { chainID: 184, rpcProvider: 'https://mainnet.base.org', stargateRouter: "0x45f1A95A4D3f3836523F5c83673c797f4d4d263B", routerETH: "0x50B6EbC2103BFEc165949CC946d739d5650d7ae4"}, "Linea": { chainID: 183, rpcProvider: 'https://rpc.linea.build', stargateRouter: "0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590", routerETH: "0x8731d54E9D02c286767d56ac03e8037C07e01e98"}, "Kava": { chainID: 177, rpcProvider: 'https://evm.kava.io', stargateRouter: "0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590", routerETH: ""}, } // Pool IDs const poolIDs = { "USDC": 1, "USDT": 2, "DAI": 3, "FRAX": 7, "USDD": 11, "ETH": 13, "sUSD": 14, "LUSD": 15, "MAI": 16, "METIS": 17, "metis.USDT": 19 } // ABI for ERC20 const erc20ABI = [ { "constant": true, "inputs": [ { "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" } ], "name": "allowance", "outputs": [{ "name": "", "type": "uint256" }], "type": "function" }, { "constant": false, "inputs": [ { "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" } ], "name": "approve", "outputs": [{ "name": "", "type": "bool" }], "type": "function" } ]; const stargateABI = [ {"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_endpoint","type":"address"},{"internalType":"uint16","name":"_mainEndpointId","type":"uint16"},{"internalType":"uint256","name":"_initialSupplyOnMainEndpoint","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"srcChainId","type":"uint16"},{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"qty","type":"uint256"}],"name":"ReceiveFromChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"dstChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"to","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"qty","type":"uint256"}],"name":"SendToChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"dstContractLookup","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"bool","name":"_useZro","type":"bool"},{"internalType":"bytes","name":"txParameters","type":"bytes"}],"name":"estimateSendTokensFee","outputs":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"zroFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"}],"name":"forceResumeReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isMain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_fromAddress","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_pause","type":"bool"}],"name":"pauseSendTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"bytes","name":"_to","type":"bytes"},{"internalType":"uint256","name":"_qty","type":"uint256"},{"internalType":"address","name":"zroPaymentAddress","type":"address"},{"internalType":"bytes","name":"adapterParam","type":"bytes"}],"name":"sendTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"uint256","name":"_configType","type":"uint256"},{"internalType":"bytes","name":"_config","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"bytes","name":"_destinationContractAddress","type":"bytes"}],"name":"setDestination","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"setReceiveVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"setSendVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"} ]; const routerABI = [ { "inputs": [ { "internalType": "uint16", "name": "_dstChainId", "type": "uint16" }, { "internalType": "uint8", "name": "_functionType", "type": "uint8" }, { "internalType": "bytes", "name": "_toAddress", "type": "bytes" }, { "internalType": "bytes", "name": "_transferAndCallPayload", "type": "bytes" }, { "components": [ { "internalType": "uint256", "name": "dstGasForCall", "type": "uint256" }, { "internalType": "uint256", "name": "dstNativeAmount", "type": "uint256" }, { "internalType": "bytes", "name": "dstNativeAddr", "type": "bytes" } ], "internalType": "struct IStargateRouter.lzTxObj", "name": "_lzTxParams", "type": "tuple" } ], "name": "quoteLayerZeroFee", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" }, { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint16", "name": "_dstChainId", "type": "uint16" }, { "internalType": "uint256", "name": "_srcPoolId", "type": "uint256" }, { "internalType": "uint256", "name": "_dstPoolId", "type": "uint256" }, { "internalType": "address payable", "name": "_refundAddress", "type": "address" }, { "internalType": "uint256", "name": "_amountLD", "type": "uint256" }, { "internalType": "uint256", "name": "_minAmountLD", "type": "uint256" }, { "components": [ { "internalType": "uint256", "name": "dstGasForCall", "type": "uint256" }, { "internalType": "uint256", "name": "dstNativeAmount", "type": "uint256" }, { "internalType": "bytes", "name": "dstNativeAddr", "type": "bytes" } ], "internalType": "struct IStargateRouter.lzTxObj", "name": "_lzTxParams", "type": "tuple" }, { "internalType": "bytes", "name": "_to", "type": "bytes" }, { "internalType": "bytes", "name": "_payload", "type": "bytes" } ], "name": "swap", "outputs": [], "stateMutability": "payable", "type": "function" }, ]; const routerETHABI = [ {"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"address payable","name":"_refundAddress","type":"address"},{"internalType":"bytes","name":"_toAddress","type":"bytes"},{"internalType":"uint256","name":"_amountLD","type":"uint256"},{"internalType":"uint256","name":"_minAmountLD","type":"uint256"}],"name":"swapETH","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"} ] async function swapOnStargate( privateKey: string, fromNetwork: string, toNetwork: string, tokenName: string, tokenAddress: string, // from token address amount: string, recipient: string ) { let router : ethers.Contract; const fromNetworkId = BlockchainData[fromNetwork as keyof typeof BlockchainData].chainID; const toNetworkId = BlockchainData[toNetwork as keyof typeof BlockchainData].chainID; const provider = new ethers.providers.JsonRpcProvider(BlockchainData[fromNetwork as keyof typeof BlockchainData].rpcProvider); const providerFeeData = await provider.getFeeData(); console.log('Fee Data: ', providerFeeData) const signer = new ethers.Wallet(privateKey, provider) if(tokenName === "STG") { const tokenContract = new ethers.Contract(tokenAddress, stargateABI, signer); // Check if we have enough allowance for Router contract // Approving spend if needed const allowance = await tokenContract.allowance(signer.address, BlockchainData[fromNetwork as keyof typeof BlockchainData].stargateRouter) if (allowance.lt(amount)) { await tokenContract.approve(BlockchainData[fromNetwork as keyof typeof BlockchainData].stargateRouter, amount, { gasPrice: providerFeeData.gasPrice, }) } const feeData = await tokenContract.estimateSendTokensFee( toNetworkId, false, "0x" ); const tx = await tokenContract.sendTokens( toNetworkId, recipient, amount, 0, "0x", { value: feeData[0], gasLimit: 600000, gasPrice: providerFeeData.gasPrice, } ); await tx.wait(); } else if(tokenName !== "ETH") { // Check if we have enough balance for specified amount for swap const tokenFromContract = new ethers.Contract(tokenAddress, erc20ABI, signer); // Check if we have enough allowance for Router contract // Approving spend if needed const allowance = await tokenFromContract.allowance(signer.address, BlockchainData[fromNetwork as keyof typeof BlockchainData].stargateRouter) if (allowance.lt(amount)) { await tokenFromContract.approve(BlockchainData[fromNetwork as keyof typeof BlockchainData].stargateRouter, amount, { gasPrice: providerFeeData.gasPrice, }) } // stargate router router = new ethers.Contract(BlockchainData[fromNetwork as keyof typeof BlockchainData].stargateRouter, routerABI, signer); // We initialize router on fromNetwork, as we will specify destination network during swap const quoteData = await router.quoteLayerZeroFee( toNetworkId, 1, signer.address, "0x", ({ dstGasForCall: 0, dstNativeAmount: 0, dstNativeAddr: "0x" }) ); const feeWei = quoteData[0]; console.log('Quote data: ', quoteData) const tx = await router.swap( toNetworkId, poolIDs[tokenName], poolIDs[tokenName], signer.address, amount, 0, {dstGasForCall: 0, dstNativeAmount: 0, dstNativeAddr: "0x"}, recipient, "0x", { value: feeWei, gasLimit: 600000, gasPrice: providerFeeData.gasPrice, } ); await tx.wait(); } else { // stargate ETH router if(!BlockchainData[fromNetwork as keyof typeof BlockchainData].routerETH) { throw new Error('Unsupported Network'); } router = new ethers.Contract(BlockchainData[fromNetwork as keyof typeof BlockchainData].routerETH, routerETHABI, signer); const tx = await router.swapETH( toNetworkId, signer.address, recipient, amount, 0, { value: amount, gasLimit: 600000, gasPrice: providerFeeData.gasPrice, } ); await tx.wait(); } }