diff --git a/.github/workflows/publish-to-npm.yml b/.github/workflows/publish-to-npm.yml index e7e67566..022d2813 100644 --- a/.github/workflows/publish-to-npm.yml +++ b/.github/workflows/publish-to-npm.yml @@ -1,4 +1,4 @@ -name: "publish to npm" +name: "Publish to NPM" on: workflow_dispatch: @@ -7,7 +7,7 @@ on: jobs: publish-to-npm: - name: "Publish to npm" + name: "Publish to NPM" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -15,7 +15,12 @@ jobs: with: node-version: "16.x" registry-url: "https://registry.npmjs.org" - - run: npm install + - name: Cache node_modules + uses: actions/cache@v2 + with: + path: node_modules + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + - run: npm ci - run: npm run build - run: npm publish env: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index db324f01..f6a3783b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,22 +9,32 @@ jobs: matrix: os: [ubuntu-22.04] arch: [amd64] - steps: + - name: Download Aptos Binary + run: | + wget --no-check-certificate https://github.com/aptos-labs/aptos-core/releases/download/aptos-cli-v1.0.4/aptos-cli-1.0.4-Ubuntu-22.04-x86_64.zip + unzip aptos-cli-1.0.4-Ubuntu-22.04-x86_64.zip + chmod +x aptos + cp aptos /usr/local/bin - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: 16 - + - name: Cache node_modules + uses: actions/cache@v2 + with: + path: node_modules + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - name: Install run: | npm ci - - name: Build run: | npm run build - + npm run build-aptos - name: Test run: | + nohup sh -c "aptos node run-local-testnet --with-faucet" > nohup.out 2> nohup.err < /dev/null & + sleep 10 npm run test diff --git a/package-lock.json b/package-lock.json index f98a7c2d..80ddc809 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@axelar-network/axelar-local-dev", - "version": "1.3.1", + "version": "1.4.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@axelar-network/axelar-local-dev", - "version": "1.3.1", + "version": "1.4.1", "license": "ISC", "dependencies": { - "@axelar-network/axelar-cgp-aptos": "^1.0.3", + "@axelar-network/axelar-cgp-aptos": "^1.0.4", "@axelar-network/axelar-cgp-near": "^1.0.0", "@axelar-network/axelar-cgp-solidity": "github:axelarnetwork/axelar-cgp-solidity#feat/forecaller-service", "@axelar-network/axelar-gmp-sdk-solidity": "^3.2.1", @@ -63,14 +63,9 @@ } }, "node_modules/@axelar-network/axelar-cgp-aptos": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@axelar-network/axelar-cgp-aptos/-/axelar-cgp-aptos-1.0.3.tgz", - "integrity": "sha512-hrRNeEeyYHwewhKPGcrvWhLf5xeEx/3LsrUZI86jfV+S7cZ0tw4KYsfKkMvGPzRNF+AlGnajV5HYAEoTdZ5qCQ==", - "hasInstallScript": true, - "dependencies": { - "aptos": "^1.3.16", - "dotenv": "^16.0.3" - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@axelar-network/axelar-cgp-aptos/-/axelar-cgp-aptos-1.0.4.tgz", + "integrity": "sha512-U/vEPzBfZvJe7uCjAObxNIVp1MK49U766nISc0fhQ50wFgPuTHVENKGmpLp5pRsjHZ8j3LaS3ogaD/P9cqqe/w==" }, "node_modules/@axelar-network/axelar-cgp-near": { "version": "1.0.0", @@ -6070,10 +6065,13 @@ "dev": true }, "node_modules/commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", - "dev": true + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", + "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", + "dev": true, + "engines": { + "node": ">=14" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -6586,14 +6584,6 @@ "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", "dev": true }, - "node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", - "engines": { - "node": ">=12" - } - }, "node_modules/duplexer3": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", @@ -9151,7 +9141,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", - "hasInstallScript": true, "optional": true, "dependencies": { "node-gyp-build": "^4.3.0" @@ -9481,7 +9470,6 @@ "version": "5.0.7", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", - "hasInstallScript": true, "optional": true, "dependencies": { "node-gyp-build": "^4.3.0" @@ -16052,6 +16040,12 @@ "node": ">=8.0.0" } }, + "node_modules/solc/node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, "node_modules/solc/node_modules/fs-extra": { "version": "0.30.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", @@ -16193,15 +16187,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/solhint/node_modules/commander": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", - "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", - "dev": true, - "engines": { - "node": ">=14" - } - }, "node_modules/solhint/node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -19290,13 +19275,9 @@ } }, "@axelar-network/axelar-cgp-aptos": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@axelar-network/axelar-cgp-aptos/-/axelar-cgp-aptos-1.0.3.tgz", - "integrity": "sha512-hrRNeEeyYHwewhKPGcrvWhLf5xeEx/3LsrUZI86jfV+S7cZ0tw4KYsfKkMvGPzRNF+AlGnajV5HYAEoTdZ5qCQ==", - "requires": { - "aptos": "^1.3.16", - "dotenv": "^16.0.3" - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@axelar-network/axelar-cgp-aptos/-/axelar-cgp-aptos-1.0.4.tgz", + "integrity": "sha512-U/vEPzBfZvJe7uCjAObxNIVp1MK49U766nISc0fhQ50wFgPuTHVENKGmpLp5pRsjHZ8j3LaS3ogaD/P9cqqe/w==" }, "@axelar-network/axelar-cgp-near": { "version": "1.0.0", @@ -23843,9 +23824,9 @@ "dev": true }, "commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", + "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", "dev": true }, "concat-map": { @@ -24265,11 +24246,6 @@ "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", "dev": true }, - "dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" - }, "duplexer3": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", @@ -31402,6 +31378,12 @@ "tmp": "0.0.33" }, "dependencies": { + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, "fs-extra": { "version": "0.30.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", @@ -31519,12 +31501,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "commander": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", - "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", - "dev": true - }, "glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", diff --git a/package.json b/package.json index 83eac531..5be59c8a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@axelar-network/axelar-local-dev", - "version": "1.4.0", + "version": "1.4.1", "description": "", "main": "dist/index.js", "scripts": { @@ -8,10 +8,10 @@ "test": "jest", "build-ts": "rm -rf dist && tsc", "build-contract": "rm -rf src/artifacts && hardhat compile && mv artifacts src/artifacts", - "build-aptos": "", "build-near": "cd ./src/near/contracts/test/near-axelar-contract-call-example && ./build.sh", "copy-near-wasm": "cp ./node_modules/@axelar-network/axelar-cgp-near/dist/axelar_cgp_near.wasm src/near/contracts/ && mkdir -p dist/near/contracts && cp -r src/near/contracts/axelar_cgp_near.wasm dist/near/contracts", - "build": "run-s build-contract build-aptos build-near build-ts copy-near-wasm", + "build": "run-s build-contract build-near build-ts copy-near-wasm", + "build-aptos": "bash ./aptos/build.sh", "prepare": "run-s build", "lint": "solhint 'src/contracts/**/*.sol' && eslint 'test/**/*.js'", "prettier": "prettier --write 'src/contracts/**/*.sol' 'test/**/*.js' 'src/**/*.ts'" @@ -30,12 +30,14 @@ "url": "https://github.com/axelarnetwork/axelar-local-dev/issues" }, "homepage": "https://github.com/axelarnetwork/axelar-local-dev#readme", - "files": ["dist"], + "files": [ + "dist" + ], "dependencies": { - "@axelar-network/axelar-cgp-aptos": "^1.0.3", + "@axelar-network/axelar-cgp-aptos": "^1.0.4", + "@axelar-network/axelar-cgp-near": "^1.0.0", "@axelar-network/axelar-cgp-solidity": "github:axelarnetwork/axelar-cgp-solidity#feat/forecaller-service", "@axelar-network/axelar-gmp-sdk-solidity": "^3.2.1", - "@axelar-network/axelar-cgp-near": "^1.0.0", "aptos": "^1.3.16", "ethers": "^5.6.5", "fs-extra": "^10.1.0", diff --git a/src/__tests__/aptos.spec.ts b/src/__tests__/aptos.spec.ts index c9bddbd7..5631ee11 100644 --- a/src/__tests__/aptos.spec.ts +++ b/src/__tests__/aptos.spec.ts @@ -5,28 +5,28 @@ import path from 'path'; import { ethers } from 'ethers'; const { keccak256, toUtf8Bytes } = ethers.utils; -describe.skip('aptos', () => { +describe('aptos', () => { + jest.setTimeout(60000); let client: any; - it('should be able to deploy axelar framework modules', async () => { + beforeEach(async () => { client = await createAptosNetwork(); }); it('should be able to call approve_contract_call', async () => { - const commandId = new HexString('0x350f78556f96ae42254e3a639bf1808695ada7509fcbce72217e477664ec4d7b').toUint8Array(); - const payloadHash = new HexString('0x3202c028a4832bd0c3a59e1eee55d53a225f0a94cee17b16183eed85265c48cb').toUint8Array(); + const payloadHash = ethers.utils.randomBytes(32); const args = [ 'ethereum', '0xD62F0cF0801FAC878F66ebF316AB42DED01F25D8', '0x8ac1b8ff9583ac8e661c7f0ee462698c57bb7fc454f587e3fa25a57f9406acc0::hello_world', ]; - const tx = await client.approveContractCall(commandId, args[0], args[1], args[2], payloadHash); + const tx = await client.approveContractCall(ethers.utils.randomBytes(32), args[0], args[1], args[2], payloadHash); expect(tx.success).toBeTruthy(); }); it('should be able to call validate_contract_call', async () => { const compiledModules = ['hello_world.mv']; - const modulePath = '../aptos/modules/test/build/HelloWorld'; + const modulePath = '../../aptos/modules/test/build/HelloWorld'; const packageMetadata = fs.readFileSync(path.join(__dirname, modulePath, 'package-metadata.bcs')); const moduleDatas = compiledModules.map((module) => { return fs.readFileSync(path.join(__dirname, modulePath, 'bytecode_modules', module)); @@ -41,7 +41,7 @@ describe.skip('aptos', () => { console.log(`Error: ${pubTx.vm_status}`); } - const commandId = new HexString('0x350f78556f96ae42254e3a639bf1808695ada7509fcbce72217e477664ec4163').toUint8Array(); + const commandId = ethers.utils.randomBytes(32); const toSend = 'Hello Test World!'; const payload = toUtf8Bytes(toSend); const payloadHash = new HexString(keccak256(payload)).toUint8Array(); diff --git a/src/__tests__/forking.spec.ts b/src/__tests__/forking.spec.ts index 6cd81d1a..f219b66f 100644 --- a/src/__tests__/forking.spec.ts +++ b/src/__tests__/forking.spec.ts @@ -23,7 +23,7 @@ interface NetworkUsdc extends Network { } describe("forking", () => { - jest.setTimeout(600000); + jest.setTimeout(1200000); afterEach(async () => { await stopAll(); diff --git a/src/aptos/AptosNetwork.ts b/src/aptos/AptosNetwork.ts index a772b2a7..0fac9a9d 100644 --- a/src/aptos/AptosNetwork.ts +++ b/src/aptos/AptosNetwork.ts @@ -1,7 +1,7 @@ import { AptosAccount, AptosClient, CoinClient, HexString, TxnBuilderTypes, BCS, MaybeHexString } from 'aptos'; import fs from 'fs'; import path from 'path'; -import { sha3_256 as sha3Hash } from "@noble/hashes/sha3"; +import { sha3_256 as sha3Hash } from '@noble/hashes/sha3'; declare type EntryFunctionPayload = { function: string; @@ -32,29 +32,28 @@ export class AptosNetwork extends AptosClient { this.contractCallSequence = -1; this.payContractCallSequence = -1; this.resourceAddress = '0xe2a20d8c426eb04d882e20e78399b24123905d9f1adf95a292832805965e263a'; - - this.isGatewayDeployed().then(result => { - if(result) { - this.queryContractCallEvents().then(events => { + + this.isGatewayDeployed().then((result) => { + if (result) { + this.queryContractCallEvents().then((events) => { if (events) this.updateContractCallSequence(events); }); - this.queryPayGasContractCallEvents().then(events => { + this.queryPayGasContractCallEvents().then((events) => { if (events) this.updatePayGasContractCallSequence(events); }); - } - }) + }); } async isGatewayDeployed(): Promise { try { const resources = await this.getAccountResources(this.owner.address()); const resource_accounts = resources.find((resource) => resource.type == '0x1::resource_account::Container'); - if(!resource_accounts) return false; - const data : any = resource_accounts.data; - const gateway = data.store.data.find((entry : any) => entry.key == this.resourceAddress); + if (!resource_accounts) return false; + const data: any = resource_accounts.data; + const gateway = data.store.data.find((entry: any) => entry.key == this.resourceAddress); return gateway != null; - } catch(e) { + } catch (e) { return false; } } @@ -64,24 +63,18 @@ export class AptosNetwork extends AptosClient { const moduleDatas = compiledModules.map((module: string) => { return fs.readFileSync(path.join(modulePath, 'bytecode_modules', module)); }); - + let txHash; - - if(seed) { + + if (seed) { const data = await this.generateTransaction(this.owner.address(), { function: `0x1::resource_account::create_resource_account_and_publish_package`, type_arguments: [], - arguments: [ - HexString.ensure(seed).toUint8Array(), - packageMetadata, - moduleDatas, - ], + arguments: [HexString.ensure(seed).toUint8Array(), packageMetadata, moduleDatas], }); - + const bcsTxn = await this.signTransaction(this.owner, data); txHash = (await this.submitTransaction(bcsTxn)).hash; - - } else { txHash = await this.publishPackage( this.owner, @@ -91,8 +84,8 @@ export class AptosNetwork extends AptosClient { } const tx: any = await this.waitForTransactionWithResult(txHash); - if (tx.vm_status !== 'Executed successfully') { - console.log(`Error: ${tx.vm_status}`); + if (!tx.success) { + throw new Error(`Error: ${tx.vm_status}`); } return tx; } @@ -102,11 +95,11 @@ export class AptosNetwork extends AptosClient { } deployAxelarFrameworkModules() { - return this.deploy(path.join('node_modules/@axelar-network/axelar-cgp-aptos/aptos/modules/axelar/build/AxelarFramework'), [ - 'axelar_gas_service.mv', - 'address_utils.mv', - 'gateway.mv', - ], '0x1234'); + return this.deploy( + path.join('node_modules/@axelar-network/axelar-cgp-aptos/aptos/modules/axelar/build/AxelarFramework'), + ['axelar_gas_service.mv', 'address_utils.mv', 'gateway.mv'], + '0x1234' + ); } updateContractCallSequence(events: any[]) { @@ -162,11 +155,7 @@ export class AptosNetwork extends AptosClient { }; } - public async execute( - commandId: Uint8Array, - destinationAddress: string, - payload: Uint8Array - ) { + public async execute(commandId: Uint8Array, destinationAddress: string, payload: Uint8Array) { const tx = await this.submitTransactionAndWait(this.owner.address(), { function: `${destinationAddress}::execute`, type_arguments: [], @@ -180,11 +169,11 @@ export class AptosNetwork extends AptosClient { }; } - public async submitTransactionAndWait(from: MaybeHexString, txData: EntryFunctionPayload): Promise{ + public async submitTransactionAndWait(from: MaybeHexString, txData: EntryFunctionPayload): Promise { const rawTx = await this.generateTransaction(from, txData); const signedTx = await this.signTransaction(this.owner, rawTx); const aptosTx = await this.submitTransaction(signedTx); - return(await this.waitForTransactionWithResult(aptosTx.hash)); + return this.waitForTransactionWithResult(aptosTx.hash); } private getLatestEventSequence = (events: any[]) => { diff --git a/src/aptos/aptosNetworkUtils.ts b/src/aptos/aptosNetworkUtils.ts index e9d27d39..616b4312 100644 --- a/src/aptos/aptosNetworkUtils.ts +++ b/src/aptos/aptosNetworkUtils.ts @@ -1,5 +1,4 @@ import { FaucetClient } from 'aptos'; -import { evmRelayer } from '../relay'; import { AptosNetwork } from './AptosNetwork'; export let aptosNetwork: AptosNetwork; @@ -10,10 +9,8 @@ export interface AptosNetworkConfig { } export async function createAptosNetwork(config?: AptosNetworkConfig) { - const { nodeUrl, faucetUrl } = config || { - nodeUrl: 'http://localhost:8080', - faucetUrl: 'http://localhost:8081', - }; + const nodeUrl = config?.nodeUrl || 'http://localhost:8080'; + const faucetUrl = config?.faucetUrl || 'http://localhost:8081'; const loadingAptosNetwork = new AptosNetwork(nodeUrl); // fund the account with faucet @@ -22,9 +19,16 @@ export async function createAptosNetwork(config?: AptosNetworkConfig) { // fund the deployer address await faucet.fundAccount(loadingAptosNetwork.owner.address(), 1e10); - // deploy axelar framework modules - const tx = await loadingAptosNetwork.deployAxelarFrameworkModules(); - console.log('Deployed Axelar Framework modules:', tx.hash); + // Check if whether the gateway is deployed + const isGatewayDeployed = await loadingAptosNetwork.isGatewayDeployed(); + + // Deploy axelar framework modules, skip if already deployed + if (!isGatewayDeployed) { + const tx = await loadingAptosNetwork.deployAxelarFrameworkModules().catch((e: any) => { + console.error(e); + }); + console.log('Deployed Axelar Framework modules:', tx.hash); + } // update the sequence number const callContractEvents = await loadingAptosNetwork.queryContractCallEvents({ limit: 1000 }); @@ -36,6 +40,6 @@ export async function createAptosNetwork(config?: AptosNetworkConfig) { return aptosNetwork; } -export async function loadAptosNetwork(nodeUrl: string = 'http://localhost:8080') { +export async function loadAptosNetwork(nodeUrl = 'http://localhost:8080') { aptosNetwork = new AptosNetwork(nodeUrl); -} \ No newline at end of file +} diff --git a/test/test.js b/test/test.js deleted file mode 100644 index 56e6fc1e..00000000 --- a/test/test.js +++ /dev/null @@ -1,378 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -'use strict'; - -const chai = require('chai'); -const { - utils: { defaultAbiCoder }, - Contract, - Wallet, -} = require('ethers'); - -const { expect } = chai; -const { - createNetwork, - relay, - stopAll, - getNetwork, - utils: { defaultAccounts, setLogger, deployContract }, - setupNetwork, - getDepositAddress, - getFee, - listen, - forkNetwork, - mainnetInfo, - networks, -} = require('../dist'); - -// eslint-disable-next-line @typescript-eslint/no-empty-function -setLogger((...args) => {}); - -const BurnableMintableCappedERC20 = require('../dist/artifacts/@axelar-network/axelar-cgp-solidity/contracts/BurnableMintableCappedERC20.sol/BurnableMintableCappedERC20.json'); -const { keccak256, toUtf8Bytes } = require('ethers/lib/utils'); - -jest.setTimeout(300000); - -describe('create', () => { - let chain, blank; - it('should create a Network from no params', async () => { - chain = await createNetwork(); - }); - it('should create a Network from params', async () => { - const name = 'test'; - const id = 1234; - chain = await createNetwork({ - name, - chainId: id, - }); - expect(chain.name).to.equal('test'); - expect(chain.chainId).to.equal(id); - expect((await chain.provider.getNetwork()).chainId).to.equal(id); - }); - it('should create a Network and connect to it remotely through http', async () => { - const port = 8500; - await createNetwork({ - port, - }); - chain = await getNetwork(`http://localhost:${port}`); - }); - it('should deploy a network on a preexisting chain', async () => { - const port = 8600; - const accounts = defaultAccounts(20); - blank = require('ganache').server({ - wallet: { accounts }, - chain: { - chainId: 3000, - networkId: 3000, - }, - logging: { quiet: true }, - }); - await blank.listen(port); - chain = await setupNetwork(`http://localhost:${port}`, { - ownerKey: accounts[0].secretKey, - }); - }); - - afterEach(async () => { - await (await chain.gasService.connect(chain.ownerWallet).collectFees(chain.ownerWallet.address, [], [])).wait(); - stopAll(); - if(blank) await blank.close(); - }); -}); - -describe('token', () => { - let chain; - let user; - beforeEach(async () => { - chain = await createNetwork(); - [user] = chain.userWallets; - chain.usdc = await chain.deployToken('Axelar Wrapped USDC', 'aUSDC', 6, 0); - }); - afterEach(async () => { - stopAll(); - }); - - it('should give token to a user', async () => { - const amount = 12584532; - await chain.giveToken(user.address, 'aUSDC', amount); - expect(Number(await chain.usdc.balanceOf(user.address))).to.equal(amount); - }); - it('should deploy a new token', async () => { - const name = 'Test Token'; - const symbol = 'TEST'; - const decimals = 12; - const cap = BigInt(124932492312); - const token = await chain.deployToken(name, symbol, decimals, cap); - expect(await token.name()).to.equal(name); - expect(await token.symbol()).to.equal(symbol); - expect(Number(await token.decimals())).to.equal(decimals); - expect(BigInt(await token.cap())).to.equal(cap); - }); -}); - -describe('relay', () => { - let chain1, chain2; - let user1, user2; - beforeEach(async () => { - chain1 = await createNetwork({ seed: 1 }); - [user1] = chain1.userWallets; - chain1.usdc = await chain1.deployToken('Axelar Wrapped USDC', 'aUSDC', 6, 0); - chain2 = await createNetwork({ seed: 2 }); - [user2] = chain2.userWallets; - chain2.usdc = await chain2.deployToken('Axelar Wrapped USDC', 'aUSDC', 6, 0); - }); - afterEach(async () => { - stopAll(); - }); - describe('deposit address', () => { - it('should generate a deposit address', async () => { - const depositAddress = getDepositAddress(chain1, chain2, user2.address, 'aUSDC'); - const amount = BigInt(12423532412); - const fee = BigInt(getFee(chain1, chain2, 'aUSDC')); - await chain1.giveToken(user1.address, 'aUSDC', amount); - await (await chain1.usdc.connect(user1).transfer(depositAddress, amount)).wait(); - await relay(); - - expect(BigInt(await chain2.usdc.balanceOf(user2.address))).to.equal(amount - fee); - }); - it('should generate a deposit address to use twice', async () => { - const depositAddress = getDepositAddress(chain1, chain2, user2.address, 'aUSDC'); - const amount1 = BigInt(12423532412); - const amount2 = BigInt(5489763092348); - const fee = BigInt(getFee(chain1, chain2, 'aUSDC')); - await chain1.giveToken(user1.address, 'aUSDC', amount1); - await (await chain1.usdc.connect(user1).transfer(depositAddress, amount1)).wait(); - await relay(); - expect(BigInt(await chain2.usdc.balanceOf(user2.address))).to.equal(amount1 - fee); - - await chain1.giveToken(user1.address, 'aUSDC', amount2); - await (await chain1.usdc.connect(user1).transfer(depositAddress, amount2)).wait(); - await relay(); - expect(BigInt(await chain2.usdc.balanceOf(user2.address))).to.equal(amount1 - fee + amount2 - fee); - }); - it('should generate a deposit address remotely', async () => { - const port = 8501; - await new Promise((resolve) => { - listen(port, resolve()); - }); - const depositAddress = await getDepositAddress(chain1, chain2, user2.address, 'aUSDC', port); - const amount = BigInt(12423532412); - const fee = BigInt(getFee(chain1, chain2, 'aUSDC')); - await chain1.giveToken(user1.address, 'aUSDC', amount); - await (await chain1.usdc.connect(user1).transfer(depositAddress, amount)).wait(); - await relay(); - expect(BigInt(await chain2.usdc.balanceOf(user2.address))).to.equal(amount - fee); - }); - }); - describe('send token', () => { - it('should send some usdc over', async () => { - const amount = BigInt(1e8); - const fee = BigInt(getFee(chain1, chain2, 'aUSDC')); - await chain1.giveToken(user1.address, 'aUSDC', amount); - await (await chain1.usdc.connect(user1).approve(chain1.gateway.address, amount)).wait(); - await (await chain1.gateway.connect(user1).sendToken(chain2.name, user2.address, 'aUSDC', amount)).wait(); - await relay(); - expect(BigInt(await chain2.usdc.balanceOf(user2.address))).to.equal(amount - fee); - }); - }); - describe('call contract', () => { - let ex1, ex2; - const Executable = require('../src/artifacts/src/contracts/test/Executable.sol/Executable.json'); - - const message = 'hello there executables!'; - const payload = defaultAbiCoder.encode(['string'], [message]); - beforeEach(async () => { - ex1 = await deployContract(user1, Executable, [chain1.gateway.address, chain1.gasService.address]); - ex2 = await deployContract(user2, Executable, [chain2.gateway.address, chain1.gasService.address]); - - await await ex1.connect(user1).addSibling(chain2.name, ex2.address); - await await ex2.connect(user2).addSibling(chain1.name, ex1.address); - }); - it('should call a contract manually and fulfill the call', async () => { - await (await chain1.gateway.connect(user1).callContract(chain2.name, ex2.address, payload)).wait(); - await relay(); - const filter = chain2.gateway.filters.ContractCallApproved(); - const args = (await chain2.gateway.queryFilter(filter))[0].args; - await (await ex2.connect(user2).execute(args.commandId, chain1.name, user1.address, payload)).wait(); - - expect(await ex1.value()).to.equal(''); - expect(await ex2.value()).to.equal(message); - expect(await ex2.sourceChain()).to.equal(chain1.name); - expect(await ex2.sourceAddress()).to.equal(user1.address); - }); - it('should pay for gas and call a contract manually', async () => { - await (await chain1.gasService - .connect(user1) - .payNativeGasForContractCall(user1.address, chain2.name, ex2.address, payload, user1.address, { value: 1e6 })).wait(); - await (await chain1.gateway.connect(user1).callContract(chain2.name, ex2.address, payload)).wait(); - await relay(); - - expect(await ex1.value()).to.equal(''); - expect(await ex2.value()).to.equal(message); - expect(await ex2.sourceChain()).to.equal(chain1.name); - expect(await ex2.sourceAddress()).to.equal(user1.address); - }); - it('should call a contract through the sibling and fulfill the call', async () => { - await (await ex1.connect(user1).set(chain2.name, message)).wait(); - await relay(); - const filter = chain2.gateway.filters.ContractCallApproved(); - const args = (await chain2.gateway.queryFilter(filter))[0].args; - await (await ex2.connect(user2).execute(args.commandId, chain1.name, ex1.address, payload)).wait(); - - expect(await ex1.value()).to.equal(message); - expect(await ex2.value()).to.equal(message); - expect(await ex2.sourceChain()).to.equal(chain1.name); - expect(await ex2.sourceAddress()).to.equal(ex1.address); - }); - it('should have the sibling pay for gas and make the call', async () => { - await (await ex1.connect(user1).set(chain2.name, message, { value: BigInt(1e18) })).wait(); - await relay(); - - expect(await ex1.value()).to.equal(message); - expect(await ex2.value()).to.equal(message); - expect(await ex2.sourceChain()).to.equal(chain1.name); - expect(await ex2.sourceAddress()).to.equal(ex1.address); - }); - }); - describe('call contract with token', () => { - let ex1, ex2; - const Executable = require('../src/artifacts/src/contracts/test/ExecutableWithToken.sol/ExecutableWithToken.json'); - - const message = 'hello there executables!'; - const amount = 1234255675; - let payload; - - beforeEach(async () => { - payload = defaultAbiCoder.encode(['string', 'address'], [message, user2.address]); - ex1 = await deployContract(user1, Executable, [chain1.gateway.address, chain1.gasService.address]); - ex2 = await deployContract(user2, Executable, [chain2.gateway.address, chain1.gasService.address]); - - await await ex1.connect(user1).addSibling(chain2.name, ex2.address); - await await ex2.connect(user2).addSibling(chain1.name, ex1.address); - - await chain1.giveToken(user1.address, 'aUSDC', amount); - }); - it('should call a contract manually and fulfill the call', async () => { - await (await chain1.usdc.connect(user1).approve(chain1.gateway.address, amount)).wait(); - await (await chain1.gateway.connect(user1).callContractWithToken(chain2.name, ex2.address, payload, 'aUSDC', amount)).wait(); - await relay(); - const filter = chain2.gateway.filters.ContractCallApprovedWithMint(); - const args = (await chain2.gateway.queryFilter(filter))[0].args; - await ( - await ex2.connect(user2).executeWithToken(args.commandId, chain1.name, user1.address, payload, 'aUSDC', amount) - ).wait(); - - expect(await ex1.value()).to.equal(''); - expect(await ex2.value()).to.equal(message); - expect(await ex2.sourceChain()).to.equal(chain1.name); - expect(await ex2.sourceAddress()).to.equal(user1.address); - expect((await chain2.usdc.balanceOf(user2.address)).toNumber()).to.equal(amount); - }); - it('should pay for gas and call a contract manually', async () => { - await await chain1.gasService - .connect(user1) - .payNativeGasForContractCallWithToken(user1.address, chain2.name, ex2.address, payload, 'aUSDC', amount, user1.address, { - value: 1e6, - }); - - await (await chain1.usdc.connect(user1).approve(chain1.gateway.address, amount)).wait(); - await (await chain1.gateway.connect(user1).callContractWithToken(chain2.name, ex2.address, payload, 'aUSDC', amount)).wait(); - await relay(); - - expect(await ex1.value()).to.equal(''); - expect(await ex2.value()).to.equal(message); - expect(await ex2.sourceChain()).to.equal(chain1.name); - expect(await ex2.sourceAddress()).to.equal(user1.address); - expect((await chain2.usdc.balanceOf(user2.address)).toNumber()).to.equal(amount); - }); - it('should call a contract through the sibling and fulfill the call', async () => { - await (await chain1.usdc.connect(user1).approve(ex1.address, amount)).wait(); - await (await ex1.connect(user1).setAndSend(chain2.name, message, user2.address, 'aUSDC', amount)).wait(); - await relay(); - const filter = chain2.gateway.filters.ContractCallApprovedWithMint(); - const args = (await chain2.gateway.queryFilter(filter))[0].args; - await ( - await ex2.connect(user2).executeWithToken(args.commandId, chain1.name, ex1.address, payload, 'aUSDC', amount) - ).wait(); - - expect(await ex1.value()).to.equal(message); - expect(await ex2.value()).to.equal(message); - expect(await ex2.sourceChain()).to.equal(chain1.name); - expect(await ex2.sourceAddress()).to.equal(ex1.address); - expect((await chain2.usdc.balanceOf(user2.address)).toNumber()).to.equal(amount); - }); - it('should have the sibling pay for gas and make the call', async () => { - await (await chain1.usdc.connect(user1).approve(ex1.address, amount)).wait(); - await ( - await ex1.connect(user1).setAndSend(chain2.name, message, user2.address, 'aUSDC', amount, { - value: 1e6, - }) - ).wait(); - await relay(); - - expect(await ex1.value()).to.equal(message); - expect(await ex2.value()).to.equal(message); - expect(await ex2.sourceChain()).to.equal(chain1.name); - expect(await ex2.sourceAddress()).to.equal(ex1.address); - expect((await chain2.usdc.balanceOf(user2.address)).toNumber()).to.equal(amount); - }); - }); -}); - -describe.skip('forking', () => { - afterEach(async () => { - stopAll(); - }); - it('should fork Avalanche mainnet', async () => { - const chainName = 'Avalanche'; - const chains = mainnetInfo; - const avalanche = chains.find((chain) => chain.name === chainName); - const chain = await forkNetwork(avalanche, { - ganacheOptions: { - fork: { deleteCache: true }, - }, - }); - const tokenAddress = await chain.gateway.tokenAddresses('axlUSDC'); - chain.usdc = new Contract(tokenAddress, BurnableMintableCappedERC20.abi, chain.provider); - expect(await chain.usdc.name()).to.equal('Axelar Wrapped USDC'); - const address = new Wallet(keccak256(toUtf8Bytes('random'))).address; - await chain.giveToken(address, 'uusdc', 1234); - expect(Number(await chain.usdc.balanceOf(address))).to.equal(1234); - expect(chain.gateway.address).to.equal(avalanche.gateway); - }); - it('should fork Avalanche and Ethereum and send some USDC back and forth', async () => { - const chains = mainnetInfo; - const alias = 'uusdc'; - - for (const chainName of ['Avalanche', 'Ethereum']) { - const chainInfo = chains.find((chain) => chain.name === chainName); - const chain = await forkNetwork(chainInfo); - chain.usdc = await chain.getTokenContract(alias); - } - - const avalanche = networks[0]; - const ethereum = networks[1]; - - const [userAvalanche] = avalanche.userWallets; - const [userEthereum] = ethereum.userWallets; - const amount1 = BigInt(100e6); - const fee1 = BigInt(getFee(avalanche, ethereum)); - await avalanche.giveToken(userAvalanche.address, alias, amount1); - expect(BigInt(await avalanche.usdc.balanceOf(userAvalanche.address))).to.equal(amount1); - await (await avalanche.usdc.connect(userAvalanche).approve(avalanche.gateway.address, amount1)).wait(); - await ( - await avalanche.gateway.connect(userAvalanche).sendToken(ethereum.name, userEthereum.address, avalanche.tokens[alias], amount1) - ).wait(); - - await relay(); - expect(BigInt(await ethereum.usdc.balanceOf(userEthereum.address))).to.equal(BigInt(amount1 - fee1)); - const amount2 = amount1 - fee1; - const fee2 = BigInt(getFee(ethereum, avalanche)); - await (await ethereum.usdc.connect(userEthereum).approve(ethereum.gateway.address, amount2)).wait(); - await ( - await ethereum.gateway.connect(userEthereum).sendToken(avalanche.name, userAvalanche.address, ethereum.tokens[alias], amount2) - ).wait(); - - await relay(); - expect(BigInt(await avalanche.usdc.balanceOf(userAvalanche.address))).to.equal(BigInt(amount2 - fee2)); - }); -});