From 6c028949743eb39174ec2a881bc03d61b19b0f6e Mon Sep 17 00:00:00 2001 From: Zubin Pratap Date: Thu, 5 Jun 2025 16:02:54 +1000 Subject: [PATCH 1/3] tidy testnet integration tests and README --- packages/ccip-js/README.md | 6 +++++- packages/ccip-js/jest.config.js | 13 +++++++------ packages/ccip-js/test/helpers/constants.ts | 3 ++- packages/ccip-js/test/integration-testnet.test.ts | 6 +++--- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/packages/ccip-js/README.md b/packages/ccip-js/README.md index b956122..b08703f 100644 --- a/packages/ccip-js/README.md +++ b/packages/ccip-js/README.md @@ -607,7 +607,11 @@ pnpm build-ccip-js 2. open a new terminal window and run `foundryup` followed by `anvil` - requires that you've [installed Foundry Anvil](https://book.getfoundry.sh/anvil/). Note: that Anvil is only needed for the integrations tests inside `./test` which uses the [Chainlink Local](https://github.com/smartcontractkit/chainlink-local) simulator. Actual testnet and mainnet behavior may differ from time to time and passing these tests does not guarantee testnet or mainnet behavior. -3. Back in the first terminal, inside, `packages/ccip-js` run `pnpm t:int` or `pnpm t:uint`. Note some tests are flaky - this is under investigation. You can choose to run just the mocked test or the testnet integration tests using `pnpm jest <>`. +3. Back in the first terminal, inside, `packages/ccip-js` run `export PRIVATE_KEY=xxxxxx` to set your private key and then run `pnpm t:int` or `pnpm t:uint`. + +Note some tests are flaky - this is under investigation. You can choose to run just the mocked test or the testnet integration tests using `pnpm jest <>`. + +Note further that we have set a 180000ms (3 mins) timeout on the jest config. This can cause the testnet integration test to "hang" for the entire duration. ### Contributing diff --git a/packages/ccip-js/jest.config.js b/packages/ccip-js/jest.config.js index 0168590..88f2349 100644 --- a/packages/ccip-js/jest.config.js +++ b/packages/ccip-js/jest.config.js @@ -1,8 +1,9 @@ /** @type {import('ts-jest').JestConfigWithTsJest} **/ export default { -testEnvironment: 'node', -transform: { -'^.+.tsx?$': ['ts-jest', {}], -}, -workerThreads: true, -}; \ No newline at end of file + testEnvironment: 'node', + transform: { + '^.+.tsx?$': ['ts-jest', {}], + }, + workerThreads: true, + testTimeout: 180000, +} diff --git a/packages/ccip-js/test/helpers/constants.ts b/packages/ccip-js/test/helpers/constants.ts index 3fa854f..5b38c8f 100644 --- a/packages/ccip-js/test/helpers/constants.ts +++ b/packages/ccip-js/test/helpers/constants.ts @@ -15,7 +15,8 @@ if (process.env.PRIVATE_KEY?.slice(0, 2) !== '0x') { process.env.PRIVATE_KEY = `0x${process.env.PRIVATE_KEY}` } -export const DEFAULT_ANVIL_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' +export const DEFAULT_ANVIL_PRIVATE_KEY = + '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' as Hex export const account = privateKeyToAccount(DEFAULT_ANVIL_PRIVATE_KEY) // bridge token contract diff --git a/packages/ccip-js/test/integration-testnet.test.ts b/packages/ccip-js/test/integration-testnet.test.ts index a2eb141..8f348e8 100644 --- a/packages/ccip-js/test/integration-testnet.test.ts +++ b/packages/ccip-js/test/integration-testnet.test.ts @@ -18,7 +18,7 @@ const LINK_TOKEN_FUJI = '0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846' // 6m to match https://viem.sh/docs/actions/public/waitForTransactionReceipt.html#timeout-optional, // which is called in approveRouter() // TODO @zeuslawyer: https://prajjwaldimri.medium.com/why-is-my-jest-runner-not-closing-bc4f6632c959 - tests are passing but jest is not closing. Viem transport issue? why? -const TIMEOUT = 180 * 1000 // 3m +// currently timeout set to 180000ms in jest.config.js if (!SEPOLIA_RPC_URL) { throw new Error('SEPOLIA_RPC_URL must be set') @@ -26,7 +26,8 @@ if (!SEPOLIA_RPC_URL) { if (!AVALANCHE_FUJI_RPC_URL) { throw new Error('AVALANCHE_FUJI_RPC_URL must be set') } -const privateKey = process.env.PRIVATE_KEY as `0x${string}` + +const privateKey = process.env.PRIVATE_KEY as Viem.Hex if (privateKey === DEFAULT_ANVIL_PRIVATE_KEY) { throw new Error( @@ -34,7 +35,6 @@ if (privateKey === DEFAULT_ANVIL_PRIVATE_KEY) { ) } -jest.setTimeout(TIMEOUT) describe('Integration: Fuji -> Sepolia', () => { let avalancheFujiClient: Viem.WalletClient let sepoliaClient: Viem.WalletClient From b63963109cb95b30221b26c6256b42db7048e5cc Mon Sep 17 00:00:00 2001 From: Zubin Pratap Date: Thu, 5 Jun 2025 22:25:03 +1000 Subject: [PATCH 2/3] Fix CI build error on publish dry run. For ccip-js package only. Update package.json scripts, README, and TypeScript configuration - Marked FeeQuoter as Abstract and removed inherit natspec from IFeeQuoter onconvertTokenAmount() - Cleaned up test files by removing unnecessary imports and added a completion message for integration tests. - Modified unit test script in package.json to target specific unit test files. - Updated package README with detailed local development instructions and ABI handling. - Updated tsconfig.json to enforce stricter TypeScript checks with noUnusedLocals and noUnusedParameters. - Removed unused ABI imports in api.ts and adjusted FeeQuoter contract to be abstract. --- packages/ccip-js/README.md | 9 ++++++--- packages/ccip-js/package.json | 2 +- packages/ccip-js/src/api.ts | 2 -- packages/ccip-js/src/contracts/FeeQuoter.sol | 4 ++-- packages/ccip-js/test/helpers/constants.ts | 1 + packages/ccip-js/test/helpers/contracts.ts | 2 +- packages/ccip-js/test/integration-testnet.test.ts | 6 +++++- packages/ccip-js/test/unit.test.ts | 2 -- packages/ccip-js/tsconfig.json | 6 ++++-- 9 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/ccip-js/README.md b/packages/ccip-js/README.md index b08703f..87024ea 100644 --- a/packages/ccip-js/README.md +++ b/packages/ccip-js/README.md @@ -591,7 +591,7 @@ Retrieves the transaction receipt based on the transaction hash. Returns a promi getTransactionReceipt(options: { client: Viem.Client; hash: Viem.Hash }): Promise ``` -### Development +### Development (For developing this CCIP-JS package locally) #### Build @@ -600,6 +600,9 @@ pnpm i -w pnpm build-ccip-js ``` +Note that when the above `build-ccip-js` step is run, the contracts located in `./src/contracts` are compiled and ABIs and artifacts are emitted into the `../ccip-js/artifacts` +folder. From there, the relevant ABI arrays must be manually moved to `./src/abi` , and just the ABI array is pasted into the corresponding file in `./src/abi`. However the files in `./artifacts-compile` contain objects with both the abi and the bytecode and are used in the unit test files with Viem's test clients. + #### Running tests 1. cd into `packages/ccip-js` and then run `pnpm install` OR from the project root you can run `pnpm i -w` @@ -607,11 +610,11 @@ pnpm build-ccip-js 2. open a new terminal window and run `foundryup` followed by `anvil` - requires that you've [installed Foundry Anvil](https://book.getfoundry.sh/anvil/). Note: that Anvil is only needed for the integrations tests inside `./test` which uses the [Chainlink Local](https://github.com/smartcontractkit/chainlink-local) simulator. Actual testnet and mainnet behavior may differ from time to time and passing these tests does not guarantee testnet or mainnet behavior. -3. Back in the first terminal, inside, `packages/ccip-js` run `export PRIVATE_KEY=xxxxxx` to set your private key and then run `pnpm t:int` or `pnpm t:uint`. +3. Back in the first terminal, inside, `packages/ccip-js` run `export PRIVATE_KEY=xxxxxx` to set your private key and then run `pnpm t:int` or `pnpm t:uint`. Note some tests are flaky - this is under investigation. You can choose to run just the mocked test or the testnet integration tests using `pnpm jest <>`. -Note further that we have set a 180000ms (3 mins) timeout on the jest config. This can cause the testnet integration test to "hang" for the entire duration. +Note further that we have set a 180000ms (3 mins) timeout on the jest config. This can cause the testnet integration test to "hang" for the entire duration. ### Contributing diff --git a/packages/ccip-js/package.json b/packages/ccip-js/package.json index ab9ce13..4060589 100644 --- a/packages/ccip-js/package.json +++ b/packages/ccip-js/package.json @@ -15,7 +15,7 @@ "lint": "eslint 'src/**/*.{ts,js}'", "format": "prettier --write 'src/**/*.{ts,js,json,md}'", "t:int": "jest --coverage -u --testMatch=\"**/integration-testnet.test.ts\" --detectOpenHandles", - "t:unit": "jest --coverage -u -t=\"Unit\"", + "t:unit": "jest --coverage -u --testMatch=\"**/unit.test.ts\" ", "test:hh": "hardhat test" }, "devDependencies": { diff --git a/packages/ccip-js/src/api.ts b/packages/ccip-js/src/api.ts index 0bf9c62..7726acb 100644 --- a/packages/ccip-js/src/api.ts +++ b/packages/ccip-js/src/api.ts @@ -14,8 +14,6 @@ import OnRampABI from './abi/OnRamp.json' import OnRampABI_1_6 from './abi/OnRamp_1_6.json' import IERC20ABI from './abi/IERC20Metadata.json' import TokenPoolABI from './abi/TokenPool.json' -import PriceRegistryABI from './abi/PriceRegistry.json' -import FeeQuoterABI from './abi/FeeQuoter.json' import TokenAdminRegistryABI from './abi/TokenAdminRegistry.json' import { TRANSFER_STATUS_FROM_BLOCK_SHIFT, ExecutionStateChangedABI } from './config' import { parseAbi } from 'viem' diff --git a/packages/ccip-js/src/contracts/FeeQuoter.sol b/packages/ccip-js/src/contracts/FeeQuoter.sol index f91798c..c376a6e 100644 --- a/packages/ccip-js/src/contracts/FeeQuoter.sol +++ b/packages/ccip-js/src/contracts/FeeQuoter.sol @@ -11,7 +11,7 @@ import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet /// @notice The FeeQuoter contract responsibility is to store the current gas price in USD for a given destination chain, /// and the price of a token in USD allowing the owner or priceUpdater to update this value. -contract FeeQuoter is IFeeQuoter, OwnerIsCreator { +abstract contract FeeQuoter is IFeeQuoter, OwnerIsCreator { using EnumerableSet for EnumerableSet.AddressSet; using USDPriceWith18Decimals for uint224; @@ -124,7 +124,7 @@ contract FeeQuoter is IFeeQuoter, OwnerIsCreator { return (_getValidatedTokenPrice(feeToken), gasPrice.value); } - /// @inheritdoc IFeeQuoter + /// @dev this function assumed that no more than 1e59 dollar, is sent as payment. /// If more is sent, the multiplication of feeTokenAmount and feeTokenValue will overflow. /// Since there isn't even close to 1e59 dollars in the world economy this is safe. diff --git a/packages/ccip-js/test/helpers/constants.ts b/packages/ccip-js/test/helpers/constants.ts index 5b38c8f..fe4b0c3 100644 --- a/packages/ccip-js/test/helpers/constants.ts +++ b/packages/ccip-js/test/helpers/constants.ts @@ -1,6 +1,7 @@ import { Address, Hash, Hex, TransactionReceipt } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import dotenv from 'dotenv' + import bridgeJson from '../../artifacts-compile/BridgeToken.json' import onRampJson from '../../artifacts-compile/EVM2EVMOnRamp.json' import routerJson from '../../artifacts-compile/Router.json' diff --git a/packages/ccip-js/test/helpers/contracts.ts b/packages/ccip-js/test/helpers/contracts.ts index 5521c9e..85c1551 100644 --- a/packages/ccip-js/test/helpers/contracts.ts +++ b/packages/ccip-js/test/helpers/contracts.ts @@ -1,4 +1,4 @@ -import { formatEther, getContract, type Address, type Hex } from 'viem' +import { getContract, type Address, type Hex } from 'viem' import { account, bridgeTokenAbi, diff --git a/packages/ccip-js/test/integration-testnet.test.ts b/packages/ccip-js/test/integration-testnet.test.ts index 8f348e8..dad1758 100644 --- a/packages/ccip-js/test/integration-testnet.test.ts +++ b/packages/ccip-js/test/integration-testnet.test.ts @@ -1,4 +1,4 @@ -import { jest, expect, it, beforeAll, describe, afterAll } from '@jest/globals' +import { expect, it, afterAll, beforeAll, describe } from '@jest/globals' import * as CCIP from '../src/api' import * as Viem from 'viem' import { sepolia, avalancheFuji } from 'viem/chains' @@ -290,4 +290,8 @@ describe('Integration: Fuji -> Sepolia', () => { expect(ccipSend_txReceipt.to!.toLowerCase()).toEqual(AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS.toLowerCase()) }) }) + + afterAll(async () => { + console.info('✅ | Testnet Integration tests passed. Waiting for timeout...') + }) }) diff --git a/packages/ccip-js/test/unit.test.ts b/packages/ccip-js/test/unit.test.ts index d1004aa..aa28b27 100644 --- a/packages/ccip-js/test/unit.test.ts +++ b/packages/ccip-js/test/unit.test.ts @@ -2,8 +2,6 @@ import { jest, expect, it, describe, afterEach } from '@jest/globals' import * as CCIP from '../src/api' import * as Viem from 'viem' import * as viemActions from 'viem/actions' -import { sepolia } from 'viem/chains' -import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts' import { forkClient } from './helpers/clients' const ccipClient = CCIP.createClient() diff --git a/packages/ccip-js/tsconfig.json b/packages/ccip-js/tsconfig.json index 752b76f..4a42473 100644 --- a/packages/ccip-js/tsconfig.json +++ b/packages/ccip-js/tsconfig.json @@ -3,10 +3,12 @@ "lib": ["es2020", "esnext"], "target": "ES2020", "module": "esnext", - "moduleResolution": "node10", + "moduleResolution": "node", "outDir": "./dist", "rootDir": "./src", "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, @@ -15,4 +17,4 @@ "sourceMap": true }, "include": ["src"] -} \ No newline at end of file +} From 6fe0e6299140d638cb4c89f7b2be59548c4c0dfb Mon Sep 17 00:00:00 2001 From: Zubin Pratap Date: Thu, 5 Jun 2025 22:43:25 +1000 Subject: [PATCH 3/3] Use node v.20.19 to run hardhat compile as v18 was producing incorrect error that hardhat config needed .cjs extension -- when it already had that. Updating node version fixed it. --- .github/workflows/publish.yaml | 14 +++++++------- packages/ccip-js/hardhat.config.cjs | 26 +++++++++++++------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index a4d1b30..ecd3c32 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -14,17 +14,17 @@ jobs: runs-on: ubuntu-latest environment: publish permissions: - contents: read + contents: read steps: - name: Checkout the repo uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: fetch-depth: 0 - - name: Setup Node 18.x + - name: Setup Node 20.x uses: actions/setup-node@v3 with: - node-version: 18.12 + node-version: 20.19 always-auth: true - name: Install PNPM @@ -56,17 +56,17 @@ jobs: if: github.ref_name != 'main' runs-on: ubuntu-latest permissions: - contents: read + contents: read steps: - name: Checkout the repo uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: fetch-depth: 0 - - name: Setup Node 18.x + - name: Setup Node 20.x uses: actions/setup-node@v3 with: - node-version: 18.12 + node-version: 20.19 always-auth: true - name: Install PNPM @@ -90,4 +90,4 @@ jobs: pnpm build-components cd packages/ccip-react-components pnpm publish --no-git-checks --access public --dry-run - shell: bash \ No newline at end of file + shell: bash diff --git a/packages/ccip-js/hardhat.config.cjs b/packages/ccip-js/hardhat.config.cjs index 6f94d66..48436b6 100644 --- a/packages/ccip-js/hardhat.config.cjs +++ b/packages/ccip-js/hardhat.config.cjs @@ -1,20 +1,20 @@ -require("@nomicfoundation/hardhat-toolbox"); -require("@nomicfoundation/hardhat-ethers"); -require("@nomicfoundation/hardhat-viem"); +require('@nomicfoundation/hardhat-toolbox') +require('@nomicfoundation/hardhat-ethers') +require('@nomicfoundation/hardhat-viem') -require("chai"); -require("mocha"); -require("ethers"); +require('chai') +require('mocha') +require('ethers') /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { - solidity: "0.8.24", + solidity: '0.8.24', solc: { - version: "0.8.24", + version: '0.8.24', }, paths: { - sources: "src/contracts", - tests: "./test", - cache: "./cache", - artifacts: "./artifacts", + sources: 'src/contracts', + tests: './test', + cache: './cache', + artifacts: './artifacts', }, -}; +}