Skip to content
This repository was archived by the owner on Mar 17, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions packages/ccip-js/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# CCIP-JS


CCIP-JS is a TypeScript library that provides a client for managing cross-chain token transfers that use Chainlink's [Cross-Chain Interoperability Protocol (CCIP)](https://docs.chain.link/ccip) routers. The library utilizes types and helper functions from [Viem](https://viem.sh/).

To learn more about CCIP, refer to the [CCIP documentation](https://docs.chain.link/ccip).
Expand Down Expand Up @@ -41,7 +40,6 @@ To learn more about CCIP, refer to the [CCIP documentation](https://docs.chain.l
- [Contributing](#contributing)
- [License](#license)


## Why CCIP-JS?

CCIP-JS provides ready-to-use typesafe methods for every step of the token transfer process.
Expand Down Expand Up @@ -69,24 +67,25 @@ Additionally, after the transfer, you may need to check the transfer status.
To install the package, use the following command:

```sh
npm install @chainlink/ccip-js viem
npm install @chainlink/ccip-js
```

Or with Yarn:

```sh
yarn add @chainlink/ccip-js viem
yarn add @chainlink/ccip-js
```

Or with PNPM:

```sh
pnpm add @chainlink/ccip-js viem
pnpm add @chainlink/ccip-js
```

## Usage

This example code covers the following steps:

- Initialize CCIP-JS Client for mainnet
- Approve tokens for transfer
- Get fee for the transfer
Expand Down Expand Up @@ -593,11 +592,13 @@ pnpm build-ccip-js

#### Running tests

```sh
pnpm i -w
anvil
pnpm test
```
1. cd into `packages/ccip-js` and then run `pnpm install` OR from the project root you can run `pnpm i -w`

2. open a new terminal window and run `anvil` - requires that you've [installed Foundry Anvil](https://book.getfoundry.sh/anvil/).

3. Back in the first terminal, inside, `packages/ccip-js` run `pnpm test`

<b?>Note:</b> that Anvil is only needed for the tests inside `./test/integration-mocked.test.ts` 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.

### Contributing

Expand Down
4 changes: 2 additions & 2 deletions packages/ccip-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@chainlink/ccip-js",
"version": "0.2.2",
"version": "0.2.3",
"private": false,
"main": "dist/api.js",
"types": "dist/api.d.ts",
Expand All @@ -15,7 +15,7 @@
"lint": "eslint 'src/**/*.{ts,js}'",
"format": "prettier --write 'src/**/*.{ts,js,json,md}'",
"pretest": "anvil --block-time 2",
"t:int": "jest --coverage -u -t=\"Integration\"",
"t:int": "jest --coverage -u --testMatch=\"**/integration-*.test.ts\" --detectOpenHandles",
"t:unit": "jest --coverage -u -t=\"Unit\"",
"test": "jest --coverage",
"test:hh": "hardhat test"
Expand Down
9 changes: 4 additions & 5 deletions packages/ccip-js/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,7 @@ export interface Client {
* @param {Viem.Address} options.routerAddress - The address of the router contract on the source blockchain.
* @param {string} options.destinationChainSelector - The selector for the destination chain.
* @param {Viem.Address} options.tokenAddress - The address of the token contract on the source blockchain.
* @returns {Promise<boolean>} A promise that resolves to a boolean value indicating whether the token
* is supported on the destination chain.
* @returns {Promise<boolean>} A promise that resolves to the Token Admin Registry Contract address on the source chain.
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
Expand Down Expand Up @@ -617,7 +616,7 @@ export const createClient = (): Client => {

const approveTxHash = await writeContract(options.client, {
chain: options.client.chain,
account: options.client.account!.address,
account: options.client.account!,
abi: IERC20ABI,
address: options.tokenAddress,
functionName: 'approve',
Expand Down Expand Up @@ -852,7 +851,7 @@ export const createClient = (): Client => {
address: options.routerAddress,
functionName: 'ccipSend',
args: buildArgs(options),
account: options.client.account!.address,
account: options.client.account!,
...(!options.feeTokenAddress && {
value: await getFee(options),
}),
Expand Down Expand Up @@ -905,7 +904,7 @@ export const createClient = (): Client => {
address: options.routerAddress,
functionName: 'ccipSend',
args: buildArgs(options),
account: options.client.account!.address,
account: options.client.account!,
...(!options.feeTokenAddress && {
value: await getFee(options),
}),
Expand Down
4 changes: 2 additions & 2 deletions packages/ccip-js/test/helpers/clients.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { account } from './constants'
import { createTestClient, http, publicActions, walletActions } from 'viem'
import { hardhat, sepolia } from 'viem/chains'
import { sepolia, anvil } from 'viem/chains'

export const testClient = createTestClient({
chain: hardhat,
chain: anvil,
transport: http(),
mode: 'anvil',
account,
Expand Down
20 changes: 12 additions & 8 deletions packages/ccip-js/test/helpers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,26 @@ import routerJson from '../../artifacts-compile/Router.json'
import simulatorJson from '../../artifacts-compile/CCIPLocalSimulator.json'
import priceRegistryJson from '../../artifacts-compile/PriceRegistry.json'

// load.env file for private key
// load.env file for private key
// replace with your own private key (optional)
dotenv.config()

// default anvil PK
export const privateKey =
(process.env.PRIVATE_KEY as Hex) || '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
export const account = privateKeyToAccount(privateKey)
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 account = privateKeyToAccount(DEFAULT_ANVIL_PRIVATE_KEY)

// bridge token contract
export const { bridgeTokenAbi, bridgeTokenBin } = bridgeJson['contracts']['src/contracts/BridgeToken.sol:BridgeToken']
// note: no need to deploy
export const { onRampAbi, onRampBin } = onRampJson['contracts']['src/contracts/EVM2EVMOnRamp.sol:EVM2EVMOnRamp']
export const { routerAbi, routerBin } = routerJson['contracts']['src/contracts/Router.sol:Router']
export const { simulatorAbi, simulatorBin } = simulatorJson['contracts']['src/contracts/CCIPLocalSimulator.sol:CCIPLocalSimulator']
export const { priceRegistryAbi, priceRegistryBin } = priceRegistryJson['contracts']['src/contracts/PriceRegistry.sol:PriceRegistry']
export const { simulatorAbi, simulatorBin } =
simulatorJson['contracts']['src/contracts/CCIPLocalSimulator.sol:CCIPLocalSimulator']
export const { priceRegistryAbi, priceRegistryBin } =
priceRegistryJson['contracts']['src/contracts/PriceRegistry.sol:PriceRegistry']

// CCIP testing data for simulations
export const ccipTxHash = '0xc55d92b1212dd24db843e1cbbcaebb1fffe3cd1751313e0fd02cf26bf72b359e'
Expand Down Expand Up @@ -119,4 +123,4 @@ export const ccipTxReceipt: TransactionReceipt = {
transactionHash: ccipTxHash,
transactionIndex: 0,
type: 'eip1559',
}
}
Loading