Skip to content

Feat/support decimals for Hedera #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jun 26, 2025
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
48 changes: 38 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@

[![License](https://img.shields.io/badge/license-MIT-blue)](https://github.com/smartcontractkit/ccip-javascript-sdk/blob/main/LICENSE)
[![SDK Documentation](https://img.shields.io/static/v1?label=sdk-docs&message=latest&color=blue)](https://docs.chain.link/ccip/ccip-javascript-sdk/)

</div>

# CCIP JavaScript SDK

The CCIP JavaScript SDK includes two packages:
- [`ccip-js`](/packages/ccip-js/README.md): 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.
- [`ccip-react-components`](/packages/ccip-react-components/README.md): A set of prebuilt ready-to-use UI components built on top of `ccip-js`.
### Start here

The CCIP JavaScript SDK is a monorepo for two packages:

- [`ccip-js`](/packages/ccip-js/README.md): 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.
- [`ccip-react-components`](/packages/ccip-react-components/README.md): A set of prebuilt ready-to-use React UI components. This package depends on `ccip-js`.

Using both packages, you can add a fully featured CCIP bridge to your app that can be styled to match your app design.

To view more detailed documentation and more examples, visit the [Chainlink Javascript SDK Documentation](https://docs.chain.link/ccip/ccip-javascript-sdk/).
Using both packages, you can add a fully featured CCIP bridge to your app that can be styled to match your app design.

To view more detailed documentation and more examples, visit the [Chainlink Javascript SDK Documentation](https://docs.chain.link/ccip/ccip-javascript-sdk/). Development specific information is also found in individual READMEs inside the `./packages/<<PACKAGE_NAME>>` directory.

There is also an example implementation of a front end NextJS app that uses these packages in `./examples/nextjs`. That has its own README as well.

### Prerequisites

Expand All @@ -29,7 +35,6 @@ git clone https://github.com/smartcontractkit/ccip-javascript-sdk.git

3. Run `pnpm install`


### Run the example app

```sh
Expand All @@ -42,9 +47,12 @@ pnpm dev-example

### Build packages

If you want to make changes to the package code, you need to rebuild the packages and make sure package.json file to point to the updated local versions.
If you want to make changes to the package code, you need to rebuild the packages.
Then:

Make sure to build the `ccip-js` package before you build the `ccip-react-components` package. The React components depend on the JS package.
1. Make sure to build the `ccip-js` package before you build the `ccip-react-components` package. The React components depend on the JS package.

2. Make sure your client's package.json file to points to the updated local versions or use npm link or equivalent in your downstream client code. You can see examples of this in the steps below.

Follow these steps:

Expand Down Expand Up @@ -73,9 +81,29 @@ pnpm build-components
"@chainlink/ccip-react-components": "link:../../packages/ccip-react-components",
```

## Contributing

Contributions to either repos are welcome! Please open an issue or submit a pull request using the process below.

1. Fork the repository.
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/ccip-javascript-sdk.git`
3. Navigate to directory: `cd ccip-javascript-sdk`
4. Fetch all branches: `git fetch origin`
5. Switch to develop branch: `git checkout develop`
6. Install dependencies: `pnpm install`
7. Create a feature branch: `git checkout -b feature/my-feature`
8. Commit your changes
9. Push to the branch (git push origin feature/my-feature).
10. Open a pull request from your fork to the `develop` branch of this repo.

🚨 Always branch off from `develop` when creating your feature branch.

## Resources

- [ccip-js README](./packages/ccip-js/README.md)
- [ccip-react-components README](./packages/ccip-react-components/README.md)
- [examples/nextjs README](./examples/nextjs/README.md)
- [Chainlink CCIP Javascript SDK Documentation](https://docs.chain.link/ccip/ccip-javascript-sdk/)
- [Chainlink CCIP Documentation](https://docs.chain.link/ccip)
- [Chainlink CCIP Directory](https://docs.chain.link/ccip/directory)
- [Chainlink Documentation](https://docs.chain.link/)
- [Chainlink Documentation](https://docs.chain.link/)
156 changes: 75 additions & 81 deletions examples/nextjs/config/networkConfig.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
AddressMap,
NetworkConfig,
Token,
} from '@chainlink/ccip-react-components';
import { AddressMap, NetworkConfig, Token } from "@chainlink/ccip-react-components";
import {
arbitrumSepolia,
avalancheFuji,
Expand All @@ -11,137 +7,135 @@ import {
optimismSepolia,
polygonAmoy,
sepolia,
} from 'viem/chains';
hederaTestnet,
} from "viem/chains";

const tokensList: Token[] = [
{
symbol: 'CCIP-BnM',
symbol: "CCIP-BnM",
address: {
[arbitrumSepolia.id]: '0xA8C0c11bf64AF62CDCA6f93D3769B88BdD7cb93D',
[avalancheFuji.id]: '0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4',
[baseSepolia.id]: '0x88A2d74F47a237a62e7A51cdDa67270CE381555e',
[bscTestnet.id]: '0xbFA2ACd33ED6EEc0ed3Cc06bF1ac38d22b36B9e9',
[optimismSepolia.id]: '0x8aF4204e30565DF93352fE8E1De78925F6664dA7',
[polygonAmoy.id]: '0xcab0EF91Bee323d1A617c0a027eE753aFd6997E4',
[sepolia.id]: '0xFd57b4ddBf88a4e07fF4e34C487b99af2Fe82a05',
[arbitrumSepolia.id]: "0xA8C0c11bf64AF62CDCA6f93D3769B88BdD7cb93D",
[avalancheFuji.id]: "0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4",
[baseSepolia.id]: "0x88A2d74F47a237a62e7A51cdDa67270CE381555e",
[bscTestnet.id]: "0xbFA2ACd33ED6EEc0ed3Cc06bF1ac38d22b36B9e9",
[optimismSepolia.id]: "0x8aF4204e30565DF93352fE8E1De78925F6664dA7",
[polygonAmoy.id]: "0xcab0EF91Bee323d1A617c0a027eE753aFd6997E4",
[sepolia.id]: "0xFd57b4ddBf88a4e07fF4e34C487b99af2Fe82a05",
[hederaTestnet.id]: "0x01Ac06943d2B8327a7845235Ef034741eC1Da352",
},
logoURL:
'https://smartcontract.imgix.net/tokens/ccip-bnm.webp?auto=compress%2Cformat',
tags: ['chainlink', 'default'],
logoURL: "https://smartcontract.imgix.net/tokens/ccip-bnm.webp?auto=compress%2Cformat",
tags: ["chainlink", "default"],
},
{
symbol: 'CCIP-LnM',
symbol: "CCIP-LnM",
address: {
[arbitrumSepolia.id]: '0x139E99f0ab4084E14e6bb7DacA289a91a2d92927',
[avalancheFuji.id]: '0x70F5c5C40b873EA597776DA2C21929A8282A3b35',
[baseSepolia.id]: '0xA98FA8A008371b9408195e52734b1768c0d1Cb5c',
[bscTestnet.id]: '0x79a4Fc27f69323660f5Bfc12dEe21c3cC14f5901',
[optimismSepolia.id]: '0x044a6B4b561af69D2319A2f4be5Ec327a6975D0a',
[polygonAmoy.id]: '0x3d357fb52253e86c8Ee0f80F5FfE438fD9503FF2',
[sepolia.id]: '0x466D489b6d36E7E3b824ef491C225F5830E81cC1',
[arbitrumSepolia.id]: "0x139E99f0ab4084E14e6bb7DacA289a91a2d92927",
[avalancheFuji.id]: "0x70F5c5C40b873EA597776DA2C21929A8282A3b35",
[baseSepolia.id]: "0xA98FA8A008371b9408195e52734b1768c0d1Cb5c",
[bscTestnet.id]: "0x79a4Fc27f69323660f5Bfc12dEe21c3cC14f5901",
[optimismSepolia.id]: "0x044a6B4b561af69D2319A2f4be5Ec327a6975D0a",
[polygonAmoy.id]: "0x3d357fb52253e86c8Ee0f80F5FfE438fD9503FF2",
[sepolia.id]: "0x466D489b6d36E7E3b824ef491C225F5830E81cC1",
},
logoURL:
'https://smartcontract.imgix.net/tokens/ccip-lnm.webp?auto=compress%2Cformat',
tags: ['chainlink', 'default'],
logoURL: "https://smartcontract.imgix.net/tokens/ccip-lnm.webp?auto=compress%2Cformat",
tags: ["chainlink", "default"],
},
{
symbol: 'GHO',
symbol: "GHO",
address: {
[arbitrumSepolia.id]: '0xb13Cfa6f8B2Eed2C37fB00fF0c1A59807C585810',
[avalancheFuji.id]: '0x9c04928Cc678776eC1C1C0E46ecC03a5F47A7723',
[baseSepolia.id]: '0x7CFa3f3d1cded0Da930881c609D4Dbf0012c14Bb',
[arbitrumSepolia.id]: "0xb13Cfa6f8B2Eed2C37fB00fF0c1A59807C585810",
[avalancheFuji.id]: "0x9c04928Cc678776eC1C1C0E46ecC03a5F47A7723",
[baseSepolia.id]: "0x7CFa3f3d1cded0Da930881c609D4Dbf0012c14Bb",
[bscTestnet.id]: undefined,
[optimismSepolia.id]: undefined,
[polygonAmoy.id]: undefined,
[sepolia.id]: '0xc4bF5CbDaBE595361438F8c6a187bDc330539c60',
[sepolia.id]: "0xc4bF5CbDaBE595361438F8c6a187bDc330539c60",
},
logoURL:
'https://smartcontract.imgix.net/tokens/gho.webp?auto=compress%2Cformat',
tags: ['stablecoin', 'default'],
logoURL: "https://smartcontract.imgix.net/tokens/gho.webp?auto=compress%2Cformat",
tags: ["stablecoin", "default"],
},
{
symbol: 'USDC',
symbol: "USDC",
address: {
[arbitrumSepolia.id]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
[avalancheFuji.id]: '0x5425890298aed601595a70AB815c96711a31Bc65',
[baseSepolia.id]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
[arbitrumSepolia.id]: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d",
[avalancheFuji.id]: "0x5425890298aed601595a70AB815c96711a31Bc65",
[baseSepolia.id]: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
[bscTestnet.id]: undefined,
[optimismSepolia.id]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
[polygonAmoy.id]: '0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582',
[sepolia.id]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
[optimismSepolia.id]: "0x5fd84259d66Cd46123540766Be93DFE6D43130D7",
[polygonAmoy.id]: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582",
[sepolia.id]: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
},
logoURL:
'https://smartcontract.imgix.net/tokens/usdc.webp?auto=compress%2Cformat',
tags: ['stablecoin', 'default'],
logoURL: "https://smartcontract.imgix.net/tokens/usdc.webp?auto=compress%2Cformat",
tags: ["stablecoin", "default"],
},
];

const chains = [
{
chain: hederaTestnet,
logoURL: "https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/hedera.svg?auto=compress%2Cformat",
},
{
chain: arbitrumSepolia,
logoURL:
'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/arbitrum.svg?auto=compress%2Cformat',
logoURL: "https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/arbitrum.svg?auto=compress%2Cformat",
},
{
chain: avalancheFuji,
logoURL:
'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/avalanche.svg?auto=compress%2Cformat',
logoURL: "https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/avalanche.svg?auto=compress%2Cformat",
},
{
chain: baseSepolia,
logoURL:
'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/base.svg?auto=compress%2Cformat',
logoURL: "https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/base.svg?auto=compress%2Cformat",
},
{
chain: bscTestnet,
logoURL:
'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/bsc.svg?auto=compress%2Cformat',
logoURL: "https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/bsc.svg?auto=compress%2Cformat",
},
{
chain: sepolia,
logoURL:
'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/ethereum.svg?auto=compress%2Cformat',
logoURL: "https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/ethereum.svg?auto=compress%2Cformat",
},
{
chain: optimismSepolia,
logoURL:
'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/optimism.svg?auto=compress%2Cformat',
logoURL: "https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/optimism.svg?auto=compress%2Cformat",
},
{
chain: polygonAmoy,
logoURL:
'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/polygon.svg?auto=compress%2Cformat',
logoURL: "https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/polygon.svg?auto=compress%2Cformat",
},
];

const linkContracts: AddressMap = {
[arbitrumSepolia.id]: '0xb1D4538B4571d411F07960EF2838Ce337FE1E80E',
[avalancheFuji.id]: '0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846',
[baseSepolia.id]: '0xE4aB69C077896252FAFBD49EFD26B5D171A32410',
[bscTestnet.id]: '0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06',
[sepolia.id]: '0x779877A7B0D9E8603169DdbD7836e478b4624789',
[optimismSepolia.id]: '0xE4aB69C077896252FAFBD49EFD26B5D171A32410',
[polygonAmoy.id]: '0x0Fd9e8d3aF1aaee056EB9e802c3A762a667b1904',
[hederaTestnet.id]: "0x326C977E6efc84E512bB9C30f76E30c160eD06FB",
[arbitrumSepolia.id]: "0xb1D4538B4571d411F07960EF2838Ce337FE1E80E",
[avalancheFuji.id]: "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846",
[baseSepolia.id]: "0xE4aB69C077896252FAFBD49EFD26B5D171A32410",
[bscTestnet.id]: "0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06",
[sepolia.id]: "0x779877A7B0D9E8603169DdbD7836e478b4624789",
[optimismSepolia.id]: "0xE4aB69C077896252FAFBD49EFD26B5D171A32410",
[polygonAmoy.id]: "0x0Fd9e8d3aF1aaee056EB9e802c3A762a667b1904",
};

const routerAddresses: AddressMap = {
[arbitrumSepolia.id]: '0x2a9C5afB0d0e4BAb2BCdaE109EC4b0c4Be15a165',
[avalancheFuji.id]: '0xF694E193200268f9a4868e4Aa017A0118C9a8177',
[baseSepolia.id]: '0xD3b06cEbF099CE7DA4AcCf578aaebFDBd6e88a93',
[bscTestnet.id]: '0xE1053aE1857476f36A3C62580FF9b016E8EE8F6f',
[sepolia.id]: '0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59',
[optimismSepolia.id]: '0x114a20a10b43d4115e5aeef7345a1a71d2a60c57',
[polygonAmoy.id]: '0x9C32fCB86BF0f4a1A8921a9Fe46de3198bb884B2',
[hederaTestnet.id]: "0x802C5F84eAD128Ff36fD6a3f8a418e339f467Ce4",
[arbitrumSepolia.id]: "0x2a9C5afB0d0e4BAb2BCdaE109EC4b0c4Be15a165",
[avalancheFuji.id]: "0xF694E193200268f9a4868e4Aa017A0118C9a8177",
[baseSepolia.id]: "0xD3b06cEbF099CE7DA4AcCf578aaebFDBd6e88a93",
[bscTestnet.id]: "0xE1053aE1857476f36A3C62580FF9b016E8EE8F6f",
[sepolia.id]: "0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59",
[optimismSepolia.id]: "0x114a20a10b43d4115e5aeef7345a1a71d2a60c57",
[polygonAmoy.id]: "0x9C32fCB86BF0f4a1A8921a9Fe46de3198bb884B2",
};

const chainSelectors = {
[arbitrumSepolia.id]: '3478487238524512106',
[avalancheFuji.id]: '14767482510784806043',
[baseSepolia.id]: '10344971235874465080',
[bscTestnet.id]: '13264668187771770619',
[sepolia.id]: '16015286601757825753',
[optimismSepolia.id]: '5224473277236331295',
[polygonAmoy.id]: '16281711391670634445',
[hederaTestnet.id]: "222782988166878823",
[arbitrumSepolia.id]: "3478487238524512106",
[avalancheFuji.id]: "14767482510784806043",
[baseSepolia.id]: "10344971235874465080",
[bscTestnet.id]: "13264668187771770619",
[sepolia.id]: "16015286601757825753",
[optimismSepolia.id]: "5224473277236331295",
[polygonAmoy.id]: "16281711391670634445",
};

export const networkConfig: NetworkConfig = {
Expand Down
9 changes: 6 additions & 3 deletions examples/nextjs/config/wagmiConfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { http, createConfig, Config } from 'wagmi';
import { http, createConfig, Config } from "wagmi";
import {
arbitrumSepolia,
avalancheFuji,
Expand All @@ -7,11 +7,13 @@ import {
optimismSepolia,
polygonAmoy,
sepolia,
} from 'viem/chains';
import { injected } from 'wagmi/connectors';
hederaTestnet,
} from "viem/chains";
import { injected } from "wagmi/connectors";

export const wagmiConfig: Config = createConfig({
chains: [
hederaTestnet,
arbitrumSepolia,
avalancheFuji,
baseSepolia,
Expand All @@ -22,6 +24,7 @@ export const wagmiConfig: Config = createConfig({
],
connectors: [injected()],
transports: {
[hederaTestnet.id]: http(),
[arbitrumSepolia.id]: http(),
[avalancheFuji.id]: http(),
[baseSepolia.id]: http(),
Expand Down
4 changes: 2 additions & 2 deletions examples/nextjs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "example-nextjs",
"version": "0.1.0",
"version": "0.1.1",
"type": "module",
"private": true,
"scripts": {
Expand All @@ -21,7 +21,7 @@
"react-dom": "18",
"typescript": "^5",
"viem": "2.21.25",
"wagmi": "^2.12.7"
"wagmi": "2.12.7"
},
"devDependencies": {
"@types/node": "^20",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"build-components": "pnpm --filter ccip-react-components run build",
"dev-example": "pnpm --filter example-nextjs run dev",
"clean": "rm -rf node_modules packages/*/node_modules packages/*/dist examples/nextjs/node_modules examples/nextjs/.next",
"test-ccip-js": "pnpm --filter ccip-js run test",
"test-ccip-js": "pnpm --filter ccip-js run t:int",
"test-components": "pnpm --filter ccip-react-components run test"
},
"devDependencies": {
Expand Down
19 changes: 5 additions & 14 deletions packages/ccip-js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -605,26 +605,17 @@ folder. From there, the relevant ABI arrays must be manually moved to `./src/abi

#### Running tests

1. cd into `packages/ccip-js` and then run `pnpm install` OR from the project root you can run `pnpm i -w`
1. Integration tests against testnets are favored in the ccip-js package.

2. open a new terminal window and run `foundryup` followed by `anvil` - requires that you've [installed Foundry Anvil](https://book.getfoundry.sh/anvil/).
<b?>Note:</b> 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.
2. Start by cd into `packages/ccip-js` and then run `pnpm install` OR from the project root you can run `pnpm i -w`

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=0x.....` to set your private key and then run `pnpm t:int`. If you're in the entire repo's root you can run the workspace filtering command `pnpm test-ccip-js`

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 <<name of test file>>`.

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 appear to "hang"until timeout completes.

### Contributing

Contributions are welcome! Please open an issue or submit a pull request on GitHub.

1. Fork the repository.
1. Create your feature branch (git checkout -b feature/my-feature).
1. Commit your changes (git commit -m 'Add some feature').
1. Push to the branch (git push origin feature/my-feature).
1. Open a pull request.
Please see the main README.

## License

Expand Down
Loading