diff --git a/README.md b/README.md index 8acd6cc0..c01ac134 100644 --- a/README.md +++ b/README.md @@ -148,12 +148,25 @@ CHILD_GAS_SERVICE_ADDRESS="0xC573c722e21eD7fadD38A8f189818433e01Ae466" ./deploy.sh ``` -4. Copy the config file with the correct addresses +4. Run the script that will send a `MAP_TOKEN` message ```shell -cp axelar-local-dev/chain-config/local.template.json axelar-local-dev/chain-config/local.json +yarn run execute evm/call-contract local Ethereum Polygon map ``` -5. Run the script to execute the `axelar-local-dev/examples/evm/call-contract/index.js` file +5. (OPTIONAL) Check the token mapping has been populated using `cast` ```shell -yarn run execute evm/call-contract local Ethereum Polygon +source .env +cast call --rpc-url $CHILD_RPC_URL "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" "rootTokenToChildToken(address)(address)" "0x38Aa1Cb12E5263eC0c6e9febC25B01116D346CD4" ``` + +6. Run the script that will send a `DEPOSIT` message +```shell +yarn run execute evm/call-contract local Ethereum Polygon deposit +``` + +7. (OPTIONAL) Check the tokens have been deposited using `cast` +```shell +source .env +cast call --rpc-url $CHILD_RPC_URL "0x3b39f73D7De57Ed2Fe85C0F30374D839dc625b93" "balanceOf(address)(uint256)" "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +``` +(Note: This assumed your address if the one associated with the above-specified private key) diff --git a/axelar-local-dev/examples/evm/call-contract/index.js b/axelar-local-dev/examples/evm/call-contract/index.js index 81663ef4..511f1403 100644 --- a/axelar-local-dev/examples/evm/call-contract/index.js +++ b/axelar-local-dev/examples/evm/call-contract/index.js @@ -4,53 +4,176 @@ const util = require('util') const { utils: { deployContract }, } = require('@axelar-network/axelar-local-dev'); +const { ethers } = require('ethers'); const ExecutableSample = rootRequire('./artifacts/examples/evm/call-contract/ExecutableSample.sol/ExecutableSample.json'); - -async function deploy(chain, wallet) { - console.log(`Deploying ExecutableSample for ${chain.name}.`); - chain.contract = await deployContract(wallet, ExecutableSample, [chain.gateway, chain.gasService]); - chain.wallet = wallet; - console.log(`Deployed ExecutableSample for ${chain.name} at ${chain.contract.address}.`); -} +const TOKEN = "0x38Aa1Cb12E5263eC0c6e9febC25B01116D346CD4" +const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" async function execute(chains, wallet, options) { - - console.log('execute call-contract'); - const args = options.args || []; const { source, destination, calculateBridgeFee } = options; - const message = args[2] || `Hello ${destination.name} from ${source.name}, it is ${new Date().toLocaleTimeString()}.`; + let functionToCall = options.args[2] + if (functionToCall === "map") { + await map(source, destination, calculateBridgeFee) + } else if (functionToCall === "deposit") { + await deposit(source, destination, calculateBridgeFee) + } else { + console.error("final arg must be either `deposit` or `map`") + process.exit(1) + } +} + +async function map(source, destination, calculateBridgeFee) { + console.log("======================================") + console.log("ATTEMPTING TO SEND `MAP_TOKEN` MESSAGE") + console.log("======================================") + console.log() async function logValue() { - console.log(destination.name) - console.log(`value at ${destination.name} is "${await destination.contract2.rootTokenToChildToken("0x38Aa1Cb12E5263eC0c6e9febC25B01116D346CD4")}"`); + let childTokenAddress = await destination.contract2.rootTokenToChildToken(TOKEN); + let rootChainChildTokenAddress = await source.contract.rootTokenToChildToken(TOKEN); + console.log("LAYER 1:") + console.log(`The L1 => L2 token mapping for token ${TOKEN.slice(0,8)}... is ${rootChainChildTokenAddress.slice(0,8)}...`) + console.log() + console.log("LAYER 2:") + console.log(`The L1 => L2 token mapping for token ${TOKEN.slice(0,8)}... is ${childTokenAddress.slice(0,8)}...`) + console.log() + + if (childTokenAddress === ZERO_ADDRESS){ + console.log("This is empty, indicating that the L1 token hasn't been deployed yet on L2. :( :(") + } else { + console.log(childTokenAddress) + console.log("This is no longer the zero address. The token has been mapped successfully!!! 📜 ☕ 📜 ☕ 📜 ☕ 📜 ☕ 📜 ☕ ") + } + console.log() } - console.log('--- Initially ---'); await logValue(); + console.log(`Calculating service fee...`); + console.log() + const fee = await calculateBridgeFee(source, destination); - console.log('fee',fee); + console.log(`Calling mapToken with a service fee of ${fee} ETH`); + console.log() + const tx = await source.contract.mapToken(TOKEN, {value: fee}) + await tx.wait() + await logValue(); + + const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + + while ((await destination.contract2.rootTokenToChildToken(TOKEN)) === ZERO_ADDRESS) { + console.log('Waiting...'); + console.log(); + await sleep(1000); + } + + await logValue(); +} + +async function deposit(source, destination, calculateBridgeFee) { + console.log("======================================") + console.log("ATTEMPTING TO SEND `DEPOSIT` MESSAGE") + console.log("======================================") + console.log() + + const depositAmount = ethers.utils.parseEther("0.1") + const userAddress = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + const basicTokenAbi = ` + [ + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "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" + } + ] + ` + + let l2TokenAddress = await destination.contract2.rootTokenToChildToken(TOKEN); + if (l2TokenAddress == ZERO_ADDRESS) { + console.log("The L1 token hasn't been mapped to L2 yet. Please run the `map` first first."); + process.exit(1); + } + + // User ethers to call the balanceOf function on the TOKEN contract + let l2TokenContract = new ethers.Contract(l2TokenAddress, basicTokenAbi, destination.contract.signer) + let l1TokenContract = new ethers.Contract(TOKEN, basicTokenAbi, source.contract.signer) + + const initialBal = await l2TokenContract.balanceOf(userAddress) + + async function logValue() { + let l2Balance = await l2TokenContract.balanceOf(userAddress) + let l1Balance = await l1TokenContract.balanceOf(userAddress) + console.log(`The user currently has ${ethers.utils.formatEther(l1Balance).toString()} L1 token(s), and ${ethers.utils.formatEther(l2Balance).toString()} L2 token(s)`) + console.log() + } + + await logValue(); + + console.log("Calling ERC20 approve...") + console.log() + + await l1TokenContract.approve(source.contract.address, depositAmount); + + console.log(`Calculating service fee...`); + console.log() + + const fee = await calculateBridgeFee(source, destination); - console.log("Calling mapToken"); - // const tx = await source.contract.deposit("0x38C50773CdA2E79a9217f40d63A8faF8fb0D4d73", "9999", {value: fee}) - const tx = await source.contract.mapToken("0x38Aa1Cb12E5263eC0c6e9febC25B01116D346CD4", {value: fee}) - await tx.wait(); + console.log(`Calling deposit with ${ethers.utils.formatEther(depositAmount).toString()} tokens, and a service fee of ${fee} ETH`); + console.log() + await source.contract.deposit(TOKEN, depositAmount, {value: fee}) const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); - while ((await destination.contract2.rootTokenToChildToken("0x38Aa1Cb12E5263eC0c6e9febC25B01116D346CD4")) == "0x0000000000000000000000000000000000000000") { + while ((await l2TokenContract.balanceOf(userAddress)).toString() === initialBal.toString()) { console.log('Waiting...'); - console.log(`value at ${destination.name} is "${await destination.contract2.rootTokenToChildToken("0x38Aa1Cb12E5263eC0c6e9febC25B01116D346CD4")}"`); - await sleep(3000); + console.log(); + await sleep(1000); } - console.log('--- After ---'); await logValue(); } module.exports = { - deploy, execute, }; \ No newline at end of file diff --git a/axelar-local-dev/scripts/libs/execute.js b/axelar-local-dev/scripts/libs/execute.js index b7444ca7..3f7654dc 100644 --- a/axelar-local-dev/scripts/libs/execute.js +++ b/axelar-local-dev/scripts/libs/execute.js @@ -50,9 +50,7 @@ async function executeEVMExample(env, chains, args, wallet, example) { chain.gateway = new Contract(chain.gateway, AxelarGatewayContract.abi, connectedWallet); chain.gasService = new Contract(chain.gasService, AxelarGasServiceContract.abi, connectedWallet); - console.log('before getAddress') const tokenAddress = await chain.gateway.tokenAddresses('aUSDC'); - console.log('tokenAddress', tokenAddress) chain.usdc = new Contract(tokenAddress, IERC20.abi, connectedWallet); } diff --git a/axelar-local-dev/scripts/libs/utils.js b/axelar-local-dev/scripts/libs/utils.js index 5d12a305..c4871aaa 100644 --- a/axelar-local-dev/scripts/libs/utils.js +++ b/axelar-local-dev/scripts/libs/utils.js @@ -25,8 +25,6 @@ function getEVMChains(env, chains = []) { const selectedChains = chains.length > 0 ? chains : getDefaultChains(env); - console.log('selectedChains', selectedChains) - if (env === 'local') { return fs .readJsonSync(path.join(__dirname, '../../chain-config/local.json')) diff --git a/axelar-local-dev/scripts/runExecute.js b/axelar-local-dev/scripts/runExecute.js index 60b3cb3d..9d98de9c 100644 --- a/axelar-local-dev/scripts/runExecute.js +++ b/axelar-local-dev/scripts/runExecute.js @@ -15,9 +15,6 @@ const example = require(getExamplePath(exampleName)); // Get the wallet. const wallet = getWallet(); -console.log('run execute'); - - // This will execute an example script. The example script must have an `execute` function. if (exampleName.split('/')[0] === 'evm') { // Get the chains for the environment. diff --git a/package.json b/package.json index cf655a7c..fc7d8bd0 100644 --- a/package.json +++ b/package.json @@ -43,4 +43,4 @@ "optionalDependencies": { "@axelar-network/axelar-local-dev-aptos": "^2.1.1-alpha.4" } -} +} \ No newline at end of file