();
+
+ return (
+
+ );
+}
diff --git a/examples/nextjs/components/ccip.tsx b/examples/nextjs/components/ccip-with-wagmi.tsx
similarity index 99%
rename from examples/nextjs/components/ccip.tsx
rename to examples/nextjs/components/ccip-with-wagmi.tsx
index 7609f6a..fa5c83d 100644
--- a/examples/nextjs/components/ccip.tsx
+++ b/examples/nextjs/components/ccip-with-wagmi.tsx
@@ -23,7 +23,7 @@ export function CCIP() {
return (
-
+ {!publicClient && !walletClient && }
{publicClient && (
<>
diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json
index 9013ba3..31039d6 100644
--- a/examples/nextjs/package.json
+++ b/examples/nextjs/package.json
@@ -13,9 +13,10 @@
"lint": "next lint"
},
"dependencies": {
- "@chainlink/ccip-js": "^0.2.1",
+ "@chainlink/ccip-js": "workspace:^",
"@chainlink/ccip-react-components": "^0.3.0",
"@tanstack/react-query": "^5.37.1",
+ "ethers": "6.13.4",
"next": "14.2.3",
"react": "18",
"react-dom": "18",
@@ -32,4 +33,4 @@
"postcss": "^8",
"tailwindcss": "^3.4.1"
}
-}
+}
\ No newline at end of file
diff --git a/packages/ccip-js/src/adapters/ethers.ts b/packages/ccip-js/src/adapters/ethers.ts
index 690febe..defe9ab 100644
--- a/packages/ccip-js/src/adapters/ethers.ts
+++ b/packages/ccip-js/src/adapters/ethers.ts
@@ -9,6 +9,13 @@ import type {
TransactionReceipt as ViemTransactionReceipt,
AbiEvent,
} from 'viem'
+
+import type {
+ ContractCallArgs,
+ TransactionArgs,
+ ReceiptArgs,
+ LogsArgs,
+} from './types'
import {
createPublicClient,
createWalletClient,
@@ -21,7 +28,7 @@ import {
isAddressEqual,
} from 'viem'
import { toAccount } from 'viem/accounts'
-import type { Provider, Signer, TypedDataField } from 'ethers'
+import type { Provider, Signer, TypedDataField, BrowserProvider } from 'ethers'
import { Contract, type TransactionReceipt as EthersTxReceipt, type TransactionResponse } from 'ethers'
import {
readContract as viemReadContract,
@@ -262,7 +269,8 @@ export function isEthersSigner(signer: any): signer is Signer {
/**
* Union of supported client types: viem Client/WalletClient, ethers Provider, or ethers Signer.
*/
-export type SupportedClient = ViemClient | WalletClient | Provider | (Signer & { provider?: Provider })
+
+export type SupportedClient = ViemClient | WalletClient | Provider | Signer | BrowserProvider
/**
* Attempts to adapt the provided client to a viem PublicClient if possible.
@@ -299,13 +307,13 @@ async function toViemWalletClient(client: SupportedClient, chain?: Chain): Promi
*/
export async function readContractCompat(
client: SupportedClient,
- args: Parameters[1] & { chain?: Chain },
+ args: ContractCallArgs,
) {
if (isEthersProvider(client) || isEthersSigner(client)) {
const provider: Provider | undefined = (isEthersSigner(client) ? (client as any).provider : client) as Provider
if (!provider) throw new Error('Unsupported client for readContract: signer has no provider')
- const contract = new Contract(args.address as Address, args.abi as any[], provider)
- return (contract as any)[(args as any).functionName](...(((args as any).args as any[]) || []))
+ const contract = new Contract(args.address, args.abi, provider)
+ return (contract as any)[args.functionName](...(args.args || []))
}
const viemClient = toViemPublicClient(client, args.chain)
if (!viemClient) throw new Error('Unsupported client for readContract')
@@ -318,18 +326,18 @@ export async function readContractCompat(
*/
export async function writeContractCompat(
client: SupportedClient,
- args: Parameters[1] & { chain?: Chain },
+ args: TransactionArgs,
) {
if (isEthersSigner(client)) {
const signer = client as Signer
- const contract = new Contract(args.address as Address, args.abi as any[], signer)
- const txResponse: TransactionResponse = await (contract as any)[(args as any).functionName](
- ...(((args as any).args as any[]) || []),
+ const contract = new Contract(args.address, args.abi, signer)
+ const txResponse: TransactionResponse = await (contract as any)[args.functionName](
+ ...(args.args || []),
{
- value: (args as any).value !== undefined ? (args as any).value.toString() : undefined,
- gasLimit: (args as any).gas,
- gasPrice: (args as any).gasPrice,
- nonce: (args as any).nonce,
+ value: args.value !== undefined ? args.value.toString() : undefined,
+ gasLimit: args.gas,
+ gasPrice: args.gasPrice,
+ nonce: args.nonce,
},
)
return txResponse.hash as Hex
@@ -345,15 +353,15 @@ export async function writeContractCompat(
*/
export async function waitForTransactionReceiptCompat(
client: SupportedClient,
- args: Parameters[1] & { chain?: Chain },
+ args: ReceiptArgs,
) {
if (isEthersProvider(client) || isEthersSigner(client)) {
const provider: Provider | undefined = (isEthersSigner(client) ? (client as any).provider : client) as Provider
if (!provider) throw new Error('Unsupported client for waitForTransactionReceipt: signer has no provider')
const maybe = await provider.waitForTransaction(
- (args as any).hash,
- (args as any).confirmations,
- (args as any).timeout,
+ args.hash,
+ args.confirmations,
+ args.timeout,
)
if (!maybe) throw new Error('Transaction receipt not found')
return formatEthersReceipt(maybe)
@@ -369,12 +377,12 @@ export async function waitForTransactionReceiptCompat(
*/
export async function getTransactionReceiptCompat(
client: SupportedClient,
- args: Parameters[1] & { chain?: Chain },
+ args: ReceiptArgs,
) {
if (isEthersProvider(client) || isEthersSigner(client)) {
const provider: Provider | undefined = (isEthersSigner(client) ? (client as any).provider : client) as Provider
if (!provider) throw new Error('Unsupported client for getTransactionReceipt: signer has no provider')
- const maybe = await provider.getTransactionReceipt((args as any).hash)
+ const maybe = await provider.getTransactionReceipt(args.hash)
if (!maybe) throw new Error('Transaction receipt not found')
return formatEthersReceipt(maybe)
}
@@ -405,17 +413,17 @@ export async function getBlockNumberCompat(client: SupportedClient, chain?: Chai
*/
export async function getLogsCompat(
client: SupportedClient,
- args: Parameters[1] & { chain?: Chain },
+ args: LogsArgs,
) {
if (isEthersProvider(client) || isEthersSigner(client)) {
const provider: Provider | undefined = (isEthersSigner(client) ? (client as any).provider : client) as Provider
if (!provider) throw new Error('Unsupported client for getLogs: signer has no provider')
- const abiEvent = (args as any).event as AbiEvent | undefined
- const address = (args as any).address as Address | undefined
- const fromBlock = (args as any).fromBlock ? ((args as any).fromBlock as bigint).toString() : undefined
- const toBlock = (args as any).toBlock ? ((args as any).toBlock as bigint).toString() : undefined
+ const abiEvent = args.event as AbiEvent | undefined
+ const address = args.address as Address | undefined
+ const fromBlock = args.fromBlock ? args.fromBlock.toString() : undefined
+ const toBlock = args.toBlock ? args.toBlock.toString() : undefined
const topics: (string | null)[] | undefined = abiEvent
- ? buildTopicsFromEventAndArgs(abiEvent, (args as any).args)
+ ? buildTopicsFromEventAndArgs(abiEvent, args.args)
: undefined
const filter: any = { address, topics, fromBlock, toBlock }
const logs = await provider.getLogs(filter)
diff --git a/packages/ccip-js/src/adapters/types.ts b/packages/ccip-js/src/adapters/types.ts
new file mode 100644
index 0000000..6d322fe
--- /dev/null
+++ b/packages/ccip-js/src/adapters/types.ts
@@ -0,0 +1,43 @@
+import type { Address, Chain, Hex, AbiEvent } from 'viem'
+
+// Custom types to eliminate 'as any' casts throughout the adapter layer
+export interface ContractCallArgs {
+ address: Address
+ // Supports both readonly and mutable ABI arrays for maximum compatibility
+ // (readonly arrays come from parseAbi, static ABIs, etc.)
+ abi: readonly any[] | any[]
+ functionName: string
+ args?: any[]
+ chain?: Chain
+}
+
+export interface TransactionArgs {
+ address: Address
+ // Supports both readonly and mutable ABI arrays for maximum compatibility
+ // (readonly arrays come from parseAbi, static ABIs, etc.)
+ abi: readonly any[] | any[]
+ functionName: string
+ args?: any[]
+ value?: bigint
+ gas?: bigint
+ gasPrice?: bigint
+ nonce?: number
+ chain?: Chain
+}
+
+export interface ReceiptArgs {
+ hash: Hex
+ confirmations?: number
+ timeout?: number
+ chain?: Chain
+}
+
+export interface LogsArgs {
+ address?: Address
+ event?: AbiEvent
+ args?: Record
+ fromBlock?: bigint
+ toBlock?: bigint
+
+ chain?: Chain
+}
diff --git a/packages/ccip-js/src/api.ts b/packages/ccip-js/src/api.ts
index 100262a..fbbb5a8 100644
--- a/packages/ccip-js/src/api.ts
+++ b/packages/ccip-js/src/api.ts
@@ -22,6 +22,7 @@ export {
getTransactionReceiptCompat,
getBlockNumberCompat,
getLogsCompat,
+ SupportedClient,
} from './adapters/ethers'
import {
@@ -734,7 +735,7 @@ export const createClient = (): Client => {
)
const feeTokens = await readCompat(options.client as any, {
- abi: parseAbi(['function getFeeTokens() returns (address[] feeTokens)']), // same signature for both PriceRegistry and FeeQuoter
+ abi: parseAbi(['function getFeeTokens() view returns (address[] feeTokens)']), // same signature for both PriceRegistry and FeeQuoter
address: priceRegistryOrFeeQuoter as Viem.Address,
functionName: 'getFeeTokens',
})
@@ -848,7 +849,7 @@ export const createClient = (): Client => {
try {
const viemChain = (options.client as any)?.chain as Viem.Chain | undefined
if (viemChain) return scaleFeeDecimals(fee, viemChain)
- } catch {}
+ } catch { }
return scaleFeeDecimals(fee)
}
diff --git a/packages/ccip-js/test/integration-testnet.test.ts b/packages/ccip-js/test/integration-testnet.test.ts
index 33033f9..c406063 100644
--- a/packages/ccip-js/test/integration-testnet.test.ts
+++ b/packages/ccip-js/test/integration-testnet.test.ts
@@ -7,6 +7,7 @@ import { sepolia, avalancheFuji, hederaTestnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import bridgeToken from '../artifacts-compile/BridgeToken.json'
import { DEFAULT_ANVIL_PRIVATE_KEY } from './helpers/constants'
+import { JsonRpcProvider, Wallet, Contract } from 'ethers'
const ccipClient = CCIP.createClient()
const bridgeTokenAbi = bridgeToken.contracts['src/contracts/BridgeToken.sol:BridgeToken'].bridgeTokenAbi
@@ -20,8 +21,7 @@ const WRAPPED_HBAR = '0xb1F616b8134F602c3Bb465fB5b5e6565cCAd37Ed'
const LINK_TOKEN_FUJI = '0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846'
const LINK_TOKEN_HEDERA = '0x90a386d59b9A6a4795a011e8f032Fc21ED6FEFb6'
-// 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?
// currently timeout set to 180000ms in jest.config.js
@@ -36,11 +36,11 @@ const privateKey = process.env.PRIVATE_KEY as Viem.Hex
if (privateKey === DEFAULT_ANVIL_PRIVATE_KEY) {
throw new Error(
- "Developer's PRIVATE_KEY for Ethereum Sepolia and Avalanche Fuji must be set for integration testing on",
+ "Developer's PRIVATE_KEY for Ethereum Sepolia and Avalanche Fuji must be set in terminal for integration testing on testnet",
)
}
-describe('Integration: Fuji -> Sepolia', () => {
+describe('[Viem]Integration: Fuji -> Sepolia', () => {
let avalancheFujiClient: Viem.WalletClient
let sepoliaClient: Viem.WalletClient
let bnmToken_fuji: any
@@ -108,7 +108,7 @@ describe('Integration: Fuji -> Sepolia', () => {
routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
})
- expect(avalancheFujiOnRampAddress).toEqual('0x75b9a75Ee1fFef6BE7c4F842a041De7c6153CF4E')
+ expect(avalancheFujiOnRampAddress).toEqual('0x75b9a75Ee1fFef6BE7c4F842a041De7c6153CF4E' as `0x${string}`)
})
it('lists supported fee tokens', async function () {
@@ -131,7 +131,7 @@ describe('Integration: Fuji -> Sepolia', () => {
// this implicitly asserts that the values are defined as well.
expect(typeof tokens).toBe('bigint')
- expect(typeof lastUpdated).toBe('number')
+ expect(typeof lastUpdated).toBe('bigint') // Changed to bigint
expect(typeof isEnabled).toBe('boolean')
expect(typeof capacity).toBe('bigint')
expect(typeof rate).toBe('bigint')
@@ -335,7 +335,7 @@ describe('Integration: Fuji -> Sepolia', () => {
expect(ccipSend_txReceipt).toBeDefined()
expect(ccipSend_txReceipt.status).toEqual('success')
expect(ccipSend_txReceipt.from.toLowerCase()).toEqual(avalancheFujiClient.account!.address.toLowerCase())
- expect(ccipSend_txReceipt.to!.toLowerCase()).toEqual(AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS.toLowerCase())
+ expect(ccipSend_txReceipt.to!.toLowerCase()).toEqual(AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS.toLowerCase() as `0x${string}`)
})
})
@@ -344,7 +344,7 @@ describe('Integration: Fuji -> Sepolia', () => {
})
})
-describe('√ (Hedera(custom decimals) -> Sepolia) all critical functionality in CCIP Client', () => {
+describe('[Viem](Hedera(custom decimals) -> Sepolia) all critical functionality in CCIP Client', () => {
let hederaTestnetClient: Viem.WalletClient
let sepoliaClient: Viem.WalletClient
let bnmToken_hedera: any
@@ -561,6 +561,323 @@ describe('√ (Hedera(custom decimals) -> Sepolia) all critical functionality in
expect(ccipSend_txReceipt).toBeDefined()
expect(ccipSend_txReceipt.status).toEqual('success')
expect(ccipSend_txReceipt.from.toLowerCase()).toEqual(hederaTestnetClient.account!.address.toLowerCase())
- expect(ccipSend_txReceipt.to!.toLowerCase()).toEqual(HEDERA_TESTNET_CCIP_ROUTER_ADDRESS.toLowerCase())
+ expect(ccipSend_txReceipt.to!.toLowerCase()).toEqual(HEDERA_TESTNET_CCIP_ROUTER_ADDRESS.toLowerCase() as `0x${string}`)
+ })
+})
+
+describe.only('[Ethers]Integration: Fuji -> Sepolia', () => {
+ let avalancheFujiProvider: JsonRpcProvider
+ let avalancheFujiSigner: Wallet
+ let sepoliaProvider: JsonRpcProvider
+ let sepoliaSigner: Wallet
+ let bnmToken_fuji: any
+ let _messageId: `0x${string}`
+ let tokenTransfer_txHash: `0x${string}`
+
+ const AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS = '0xF694E193200268f9a4868e4Aa017A0118C9a8177'
+ const approvedAmount = parseEther('0.000000001')
+
+ beforeAll(async () => {
+ avalancheFujiProvider = new JsonRpcProvider(AVALANCHE_FUJI_RPC_URL)
+ try {
+ await avalancheFujiProvider.ready
+ await avalancheFujiProvider.getBlockNumber()
+ } catch (error) {
+ console.log('ERROR : avalancheFujiProvider', error)
+ }
+
+ avalancheFujiSigner = new Wallet(privateKey, avalancheFujiProvider)
+
+ sepoliaProvider = new JsonRpcProvider(SEPOLIA_RPC_URL)
+ sepoliaSigner = new Wallet(privateKey, sepoliaProvider)
+
+ bnmToken_fuji = new Contract(
+ '0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4', // CCIP BnM on Avalanche Fuji
+ bridgeTokenAbi,
+ avalancheFujiSigner,
+ )
+
+ // Check that contract is properly instantiated
+ if (!bnmToken_fuji.target) {
+ throw new Error('Contract target is undefined - contract not properly instantiated')
+ }
+ expect(bnmToken_fuji.target).toEqual('0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4' as `0x${string}`)
+
+ const bnmBalance = await bnmToken_fuji.balanceOf(avalancheFujiSigner.address)
+ if (parseInt(bnmBalance) <= approvedAmount) {
+ await bnmToken_fuji.drip(avalancheFujiSigner.address)
+ console.log(' ℹ️ | Dripped 1 CCIP BnM token to account: ', avalancheFujiSigner.address)
+ }
+ })
+
+ describe('√ (Fuji -> Sepolia) all critical functionality in CCIP Client', () => {
+ it('should approve BnM spend, given valid input', async () => {
+ const ccipApprove = await ccipClient.approveRouter({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ amount: approvedAmount,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ waitForReceipt: true,
+ })
+
+ // ccipApprove.txReceipt!.status == 'success' && console.log(' | Approved CCIP BnM token on Avalanche Fuji'
+ await expect(ccipApprove.txReceipt!.status).toEqual('success')
+ })
+
+ it('fetches token allowance', async function () {
+ const allowance = await ccipClient.getAllowance({
+ client: avalancheFujiSigner,
+ account: avalancheFujiSigner.address as `0x${string}`,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ })
+ expect(allowance).toEqual(approvedAmount)
+ })
+
+ it('returns on-ramp address', async function () {
+ const avalancheFujiOnRampAddress = await ccipClient.getOnRampAddress({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ })
+ expect(avalancheFujiOnRampAddress).toEqual('0x75b9a75Ee1fFef6BE7c4F842a041De7c6153CF4E' as `0x${string}`)
+ })
+
+ it.only('lists supported fee tokens', async function () {
+ const result = await ccipClient.getSupportedFeeTokens({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ })
+ expect(result.length).toEqual(2)
+ expect(result.includes(LINK_TOKEN_FUJI)).toBe(true)
+ expect(result.includes(WRAPPED_NATIVE_AVAX)).toBe(true)
+ })
+
+ it('fetched lane rate refill limits are defined', async function () {
+ const { tokens, lastUpdated, isEnabled, capacity, rate } = await ccipClient.getLaneRateRefillLimits({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ })
+
+ // this implicitly asserts that the values are defined as well.
+ expect(typeof tokens).toBe('bigint')
+ expect(typeof lastUpdated).toBe('bigint') // Both Ethers and Viem return bigint for timestamps
+ expect(typeof isEnabled).toBe('boolean')
+ expect(typeof capacity).toBe('bigint')
+ expect(typeof rate).toBe('bigint')
+ })
+
+ it('returns token rate limit by lane', async function () {
+ const { tokens, lastUpdated, isEnabled, capacity, rate } = await ccipClient.getTokenRateLimitByLane({
+ client: avalancheFujiSigner, // Use signer for ethers
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ supportedTokenAddress: bnmToken_fuji.target as `0x${string}`,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ })
+
+ // this implicitly asserts that the values are defined as well.
+ expect(typeof tokens).toBe('bigint')
+ expect(typeof lastUpdated).toBe('bigint') // Both Ethers and Viem return bigint for timestamps
+ expect(typeof isEnabled).toBe('boolean')
+ expect(typeof capacity).toBe('bigint')
+ expect(typeof rate).toBe('bigint')
+ })
+
+ it('returns fee estimate', async function () {
+ const fee_link = await ccipClient.getFee({
+ client: avalancheFujiSigner, // Use signer for ethers
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ amount: approvedAmount,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ destinationAccount: sepoliaSigner.address as `0x${string}`,
+ feeTokenAddress: LINK_TOKEN_FUJI,
+ })
+ const fee_native = await ccipClient.getFee({
+ client: avalancheFujiSigner, // Use signer for ethers
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ amount: approvedAmount,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ destinationAccount: sepoliaSigner.address as `0x${string}`,
+ feeTokenAddress: WRAPPED_NATIVE_AVAX,
+ })
+
+ expect(fee_link).toBeGreaterThan(1000n)
+ expect(fee_native).toBeGreaterThan(1000n)
+ })
+ it('returns token admin registry', async function () {
+ const result = await ccipClient.getTokenAdminRegistry({
+ client: avalancheFujiSigner, // Use signer for ethers
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ })
+
+ const CCIP_ADMIN_REGISTRY_ADDRESS = '0xA92053a4a3922084d992fD2835bdBa4caC6877e6'
+ expect(result).toEqual(CCIP_ADMIN_REGISTRY_ADDRESS as `0x${string}`)
+ })
+
+ it('checks if BnM token is supported for transfer', async function () {
+ const result = await ccipClient.isTokenSupported({
+ client: avalancheFujiSigner, // Use signer for ethers
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ })
+ expect(result).toBe(true)
+ })
+
+ it('transfers tokens | pay in LINK', async function () {
+ await ccipClient.approveRouter({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ amount: approvedAmount,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ waitForReceipt: true,
+ })
+
+ // approve LINK spend
+ const fee_link = await ccipClient.getFee({
+ client: avalancheFujiSigner, // Use signer for ethers
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ amount: approvedAmount,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ destinationAccount: sepoliaSigner.address as `0x${string}`,
+ feeTokenAddress: LINK_TOKEN_FUJI,
+ })
+ await ccipClient.approveRouter({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ amount: fee_link,
+ tokenAddress: LINK_TOKEN_FUJI,
+ waitForReceipt: true,
+ })
+ const allowance = await ccipClient.getAllowance({
+ client: avalancheFujiSigner, // Use signer for ethers
+ account: avalancheFujiSigner.address as `0x${string}`,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ })
+
+ expect(allowance).toBeGreaterThanOrEqual(approvedAmount)
+
+ const result = await ccipClient.transferTokens({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ destinationAccount: sepoliaSigner.address as `0x${string}`,
+ amount: approvedAmount,
+ feeTokenAddress: LINK_TOKEN_FUJI,
+ })
+
+ _messageId = result.messageId
+ tokenTransfer_txHash = result.txHash
+
+ expect(result.txReceipt!.status).toEqual('success')
+ })
+
+ it('transfers tokens > pays in native token', async function () {
+ await ccipClient.approveRouter({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ amount: approvedAmount,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ waitForReceipt: true,
+ })
+
+ const result = await ccipClient.transferTokens({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ tokenAddress: bnmToken_fuji.target as `0x${string}`,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ destinationAccount: sepoliaSigner.address as `0x${string}`,
+ amount: approvedAmount,
+ })
+
+ expect(result.txReceipt!.status).toEqual('success')
+ })
+
+ it('CCIP message (sending) tx OK > paid in LINK', async function () {
+ const testReceiverContract = '0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4' as `0x${string}` // using BnM token contract as receiver for testing
+ const testMessage = Viem.encodeAbiParameters(
+ [{ type: 'string', name: 'message' }],
+ ['Hello from Avalanche Fuji!'],
+ )
+
+ // Get fee in LINK and approve it
+ const fee_link = await ccipClient.getFee({
+ client: avalancheFujiSigner, // Use signer for ethers
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ destinationAccount: testReceiverContract,
+ data: testMessage,
+ feeTokenAddress: LINK_TOKEN_FUJI,
+ })
+
+ await ccipClient.approveRouter({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ amount: fee_link,
+ tokenAddress: LINK_TOKEN_FUJI,
+ waitForReceipt: true,
+ })
+
+ const result = await ccipClient.sendCCIPMessage({
+ client: avalancheFujiSigner,
+ routerAddress: AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS,
+ destinationChainSelector: SEPOLIA_CHAIN_SELECTOR,
+ destinationAccount: testReceiverContract,
+ data: testMessage,
+ feeTokenAddress: LINK_TOKEN_FUJI,
+ })
+
+ console.info(
+ `Avalanche Fuji --> Sepolia sendCCIPMessage MessageId: ${result.messageId} <> Sent to: ${testReceiverContract} on Sepolia`,
+ )
+
+ expect(result.txReceipt!.status).toEqual('success')
+ expect(result.messageId).toBeDefined()
+ expect(result.txHash).toBeDefined()
+ })
+
+ it('gets transfer status & gets transaction receipt', async function () {
+ // Skip if tokenTransfer_txHash is not set (previous test failed)
+ if (!tokenTransfer_txHash) {
+ console.warn('Skipping transfer status test - tokenTransfer_txHash not set')
+ return
+ }
+
+ const ccipSend_txReceipt = await ccipClient.getTransactionReceipt({
+ client: avalancheFujiSigner, // Use signer for ethers
+ hash: tokenTransfer_txHash,
+ })
+
+ const FUJI_CHAIN_SELECTOR = '14767482510784806043'
+ const SEPOLIA_ROUTER_ADDRESS = '0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59'
+
+ const transferStatus = await ccipClient.getTransferStatus({
+ client: sepoliaSigner, // Use signer for ethers
+ sourceChainSelector: FUJI_CHAIN_SELECTOR,
+ destinationRouterAddress: SEPOLIA_ROUTER_ADDRESS as `0x${string}`,
+ fromBlockNumber: ccipSend_txReceipt.blockNumber ? ccipSend_txReceipt.blockNumber : undefined,
+ messageId: _messageId,
+ })
+
+ expect(transferStatus).toBeDefined()
+
+ expect(ccipSend_txReceipt).toBeDefined()
+ expect(ccipSend_txReceipt.status).toEqual('success')
+ expect(ccipSend_txReceipt.from.toLowerCase()).toEqual(avalancheFujiSigner.address.toLowerCase())
+ expect(ccipSend_txReceipt.to!.toLowerCase()).toEqual(AVALANCHE_FUJI_CCIP_ROUTER_ADDRESS.toLowerCase() as `0x${string}`)
+ })
+ })
+
+ afterAll(async () => {
+ console.info('✅ | Ethers Integration tests completed. Waiting for timeout...')
})
})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0b8c23a..c207993 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -22,14 +22,17 @@ importers:
examples/nextjs:
dependencies:
'@chainlink/ccip-js':
- specifier: ^0.2.1
- version: 0.2.4(a3c99c0fb0fe13a5c24ee996cead66b3)
+ specifier: workspace:^
+ version: link:../../packages/ccip-js
'@chainlink/ccip-react-components':
specifier: ^0.3.0
version: 0.3.0(1ed1302eb82042231a950ad4c671505f)
'@tanstack/react-query':
specifier: ^5.37.1
version: 5.80.7(react@18.3.1)
+ ethers:
+ specifier: 6.13.4
+ version: 6.13.4(bufferutil@4.0.9)(utf-8-validate@5.0.10)
next:
specifier: 14.2.3
version: 14.2.3(@babel/core@7.27.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -326,10 +329,6 @@ packages:
'@asamuzakjp/css-color@3.1.1':
resolution: {integrity: sha512-hpRD68SV2OMcZCsrbdkccTw5FXjNDLo5OuqSHyHZfwweGsDWZwDJ2+gONyNAbazZclobMirACLw0lk8WVxIqxA==}
- '@babel/code-frame@7.26.2':
- resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
- engines: {node: '>=6.9.0'}
-
'@babel/code-frame@7.27.1':
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
@@ -342,10 +341,6 @@ packages:
resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==}
engines: {node: '>=6.9.0'}
- '@babel/generator@7.26.10':
- resolution: {integrity: sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==}
- engines: {node: '>=6.9.0'}
-
'@babel/generator@7.27.5':
resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==}
engines: {node: '>=6.9.0'}
@@ -515,12 +510,6 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-syntax-typescript@7.25.9':
- resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
'@babel/plugin-syntax-typescript@7.27.1':
resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==}
engines: {node: '>=6.9.0'}
@@ -3779,9 +3768,6 @@ packages:
bn.js@4.12.2:
resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==}
- bn.js@5.2.1:
- resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==}
-
bn.js@5.2.2:
resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==}
@@ -8274,12 +8260,6 @@ snapshots:
'@csstools/css-tokenizer': 3.0.3
lru-cache: 10.4.3
- '@babel/code-frame@7.26.2':
- dependencies:
- '@babel/helper-validator-identifier': 7.25.9
- js-tokens: 4.0.0
- picocolors: 1.1.1
-
'@babel/code-frame@7.27.1':
dependencies:
'@babel/helper-validator-identifier': 7.27.1
@@ -8308,14 +8288,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/generator@7.26.10':
- dependencies:
- '@babel/parser': 7.27.5
- '@babel/types': 7.26.10
- '@jridgewell/gen-mapping': 0.3.8
- '@jridgewell/trace-mapping': 0.3.25
- jsesc: 3.1.0
-
'@babel/generator@7.27.5':
dependencies:
'@babel/parser': 7.27.5
@@ -8497,11 +8469,6 @@ snapshots:
'@babel/core': 7.27.4
'@babel/helper-plugin-utils': 7.27.1
- '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
'@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.4)':
dependencies:
'@babel/core': 7.27.4
@@ -8623,44 +8590,6 @@ snapshots:
- utf-8-validate
- zod
- '@chainlink/ccip-js@0.2.4(a3c99c0fb0fe13a5c24ee996cead66b3)':
- dependencies:
- '@nomicfoundation/hardhat-chai-matchers': 2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.24.3(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)))(chai@5.2.0)(ethers@6.13.4(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.24.3(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))
- '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.24.3(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))
- '@nomicfoundation/hardhat-toolbox': 5.0.0(13680ddddf672fc71131616f3a7f7389)
- '@nomicfoundation/hardhat-viem': 2.0.6(hardhat@2.24.3(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typescript@5.8.3)(viem@2.21.25(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.67))(zod@3.25.67)
- '@openzeppelin/contracts': 5.2.0
- chai: 5.2.0
- ethers: 6.13.4(bufferutil@4.0.9)(utf-8-validate@5.0.10)
- mocha: 11.7.0
- ts-jest: 29.2.6(@babel/core@7.27.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.4))(jest@29.7.0(@types/node@20.19.1)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3)))(typescript@5.8.3)
- typescript: 5.8.3
- viem: 2.21.25(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.67)
- transitivePeerDependencies:
- - '@babel/core'
- - '@jest/transform'
- - '@jest/types'
- - '@nomicfoundation/hardhat-ignition-ethers'
- - '@nomicfoundation/hardhat-network-helpers'
- - '@nomicfoundation/hardhat-verify'
- - '@typechain/ethers-v6'
- - '@typechain/hardhat'
- - '@types/chai'
- - '@types/mocha'
- - '@types/node'
- - babel-jest
- - bufferutil
- - esbuild
- - hardhat
- - hardhat-gas-reporter
- - jest
- - solidity-coverage
- - supports-color
- - ts-node
- - typechain
- - utf-8-validate
- - zod
-
'@chainlink/ccip-react-components@0.3.0(1ed1302eb82042231a950ad4c671505f)':
dependencies:
'@chainlink/ccip-js': 0.2.4(5e3e05d9b50680c4de2bc0a3c2cf5c97)
@@ -8836,7 +8765,7 @@ snapshots:
package-manager-detector: 0.2.11
picocolors: 1.1.1
resolve-from: 5.0.0
- semver: 7.7.1
+ semver: 7.7.2
spawndamnit: 3.0.1
term-size: 2.2.1
@@ -9359,7 +9288,7 @@ snapshots:
dependencies:
'@ethersproject/bytes': 5.8.0
'@ethersproject/logger': 5.8.0
- bn.js: 5.2.1
+ bn.js: 5.2.2
'@ethersproject/bytes@5.8.0':
dependencies:
@@ -9652,7 +9581,7 @@ snapshots:
'@jest/console@29.7.0':
dependencies:
'@jest/types': 29.6.3
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
chalk: 4.1.2
jest-message-util: 29.7.0
jest-util: 29.7.0
@@ -9665,14 +9594,14 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
ansi-escapes: 4.3.2
chalk: 4.1.2
ci-info: 3.9.0
exit: 0.1.2
graceful-fs: 4.2.11
jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@22.15.32)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3))
+ jest-config: 29.7.0(@types/node@20.19.1)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3))
jest-haste-map: 29.7.0
jest-message-util: 29.7.0
jest-regex-util: 29.6.3
@@ -9700,14 +9629,14 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
ansi-escapes: 4.3.2
chalk: 4.1.2
ci-info: 3.9.0
exit: 0.1.2
graceful-fs: 4.2.11
jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@22.15.32)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@22.15.32)(typescript@5.8.3))
+ jest-config: 29.7.0(@types/node@20.19.1)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@22.15.32)(typescript@5.8.3))
jest-haste-map: 29.7.0
jest-message-util: 29.7.0
jest-regex-util: 29.6.3
@@ -9736,7 +9665,7 @@ snapshots:
dependencies:
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
jest-mock: 29.7.0
'@jest/expect-utils@29.7.0':
@@ -9754,7 +9683,7 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
'@sinonjs/fake-timers': 10.3.0
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
jest-message-util: 29.7.0
jest-mock: 29.7.0
jest-util: 29.7.0
@@ -9776,7 +9705,7 @@ snapshots:
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
'@jridgewell/trace-mapping': 0.3.25
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
chalk: 4.1.2
collect-v8-coverage: 1.0.2
exit: 0.1.2
@@ -9846,7 +9775,7 @@ snapshots:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
'@types/yargs': 17.0.33
chalk: 4.1.2
@@ -10441,16 +10370,6 @@ snapshots:
- typescript
- zod
- '@nomicfoundation/hardhat-viem@2.0.6(hardhat@2.24.3(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typescript@5.8.3)(viem@2.21.25(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.67))(zod@3.25.67)':
- dependencies:
- abitype: 0.9.10(typescript@5.8.3)(zod@3.25.67)
- hardhat: 2.24.3(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)
- lodash.memoize: 4.1.2
- viem: 2.21.25(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.67)
- transitivePeerDependencies:
- - typescript
- - zod
-
'@nomicfoundation/hardhat-viem@2.0.6(hardhat@2.24.3(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@22.15.32)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typescript@5.8.3)(viem@2.21.25(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.67))(zod@3.25.67)':
dependencies:
abitype: 0.9.10(typescript@5.8.3)(zod@3.25.67)
@@ -11702,28 +11621,28 @@ snapshots:
'@types/babel__core@7.20.5':
dependencies:
- '@babel/parser': 7.26.10
- '@babel/types': 7.26.10
+ '@babel/parser': 7.27.5
+ '@babel/types': 7.27.6
'@types/babel__generator': 7.6.8
'@types/babel__template': 7.4.4
'@types/babel__traverse': 7.20.6
'@types/babel__generator@7.6.8':
dependencies:
- '@babel/types': 7.26.10
+ '@babel/types': 7.27.6
'@types/babel__template@7.4.4':
dependencies:
- '@babel/parser': 7.26.10
- '@babel/types': 7.26.10
+ '@babel/parser': 7.27.5
+ '@babel/types': 7.27.6
'@types/babel__traverse@7.20.6':
dependencies:
- '@babel/types': 7.26.10
+ '@babel/types': 7.27.6
'@types/bn.js@5.1.6':
dependencies:
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
'@types/bn.js@5.2.0':
dependencies:
@@ -11762,7 +11681,7 @@ snapshots:
'@types/graceful-fs@4.1.9':
dependencies:
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
'@types/istanbul-lib-coverage@2.0.6': {}
@@ -12695,7 +12614,7 @@ snapshots:
acorn-walk@8.3.4:
dependencies:
- acorn: 8.14.1
+ acorn: 8.15.0
acorn@8.14.1: {}
@@ -13004,8 +12923,6 @@ snapshots:
bn.js@4.12.2: {}
- bn.js@5.2.1: {}
-
bn.js@5.2.2: {}
bowser@2.11.0: {}
@@ -15317,7 +15234,7 @@ snapshots:
'@jest/expect': 29.7.0
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
chalk: 4.1.2
co: 4.6.0
dedent: 1.5.3
@@ -15406,7 +15323,7 @@ snapshots:
- babel-plugin-macros
- supports-color
- jest-config@29.7.0(@types/node@22.15.32)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3)):
+ jest-config@29.7.0(@types/node@20.19.1)(ts-node@10.9.2(@swc/core@1.12.1)(@types/node@22.15.32)(typescript@5.8.3)):
dependencies:
'@babel/core': 7.27.4
'@jest/test-sequencer': 29.7.0
@@ -15431,8 +15348,8 @@ snapshots:
slash: 3.0.0
strip-json-comments: 3.1.1
optionalDependencies:
- '@types/node': 22.15.32
- ts-node: 10.9.2(@swc/core@1.12.1)(@types/node@20.19.1)(typescript@5.8.3)
+ '@types/node': 20.19.1
+ ts-node: 10.9.2(@swc/core@1.12.1)(@types/node@22.15.32)(typescript@5.8.3)
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
@@ -15492,7 +15409,7 @@ snapshots:
'@jest/environment': 29.7.0
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
jest-mock: 29.7.0
jest-util: 29.7.0
@@ -15502,7 +15419,7 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
'@types/graceful-fs': 4.1.9
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
anymatch: 3.1.3
fb-watchman: 2.0.2
graceful-fs: 4.2.11
@@ -15528,7 +15445,7 @@ snapshots:
jest-message-util@29.7.0:
dependencies:
- '@babel/code-frame': 7.26.2
+ '@babel/code-frame': 7.27.1
'@jest/types': 29.6.3
'@types/stack-utils': 2.0.3
chalk: 4.1.2
@@ -15541,7 +15458,7 @@ snapshots:
jest-mock@29.7.0:
dependencies:
'@jest/types': 29.6.3
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
jest-util: 29.7.0
jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
@@ -15576,7 +15493,7 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
chalk: 4.1.2
emittery: 0.13.1
graceful-fs: 4.2.11
@@ -15604,7 +15521,7 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
chalk: 4.1.2
cjs-module-lexer: 1.4.3
collect-v8-coverage: 1.0.2
@@ -15625,10 +15542,10 @@ snapshots:
jest-snapshot@29.7.0:
dependencies:
'@babel/core': 7.27.4
- '@babel/generator': 7.26.10
+ '@babel/generator': 7.27.5
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4)
- '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.27.4)
- '@babel/types': 7.26.10
+ '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.4)
+ '@babel/types': 7.27.6
'@jest/expect-utils': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
@@ -15669,7 +15586,7 @@ snapshots:
dependencies:
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
ansi-escapes: 4.3.2
chalk: 4.1.2
emittery: 0.13.1
@@ -15678,7 +15595,7 @@ snapshots:
jest-worker@29.7.0:
dependencies:
- '@types/node': 22.15.32
+ '@types/node': 20.19.1
jest-util: 29.7.0
merge-stream: 2.0.0
supports-color: 8.1.1