Skip to content
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
2 changes: 1 addition & 1 deletion ccip-cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { Format } from './commands/index.ts'
util.inspect.defaultOptions.depth = 6 // print down to tokenAmounts in requests
// generate:nofail
// `const VERSION = '${require('./package.json').version}-${require('child_process').execSync('git rev-parse --short HEAD').toString().trim()}'`
const VERSION = '1.4.2-36cc294'
const VERSION = '1.4.2-257335e'
// generate:end

const require = createRequire(import.meta.url)
Expand Down
2 changes: 1 addition & 1 deletion ccip-sdk/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const DEFAULT_TIMEOUT_MS = 30000
/** SDK version string for telemetry header */
// generate:nofail
// `export const SDK_VERSION = '${require('./package.json').version}-${require('child_process').execSync('git rev-parse --short HEAD').toString().trim()}'`
export const SDK_VERSION = '1.4.2-36cc294'
export const SDK_VERSION = '1.4.2-257335e'
// generate:end

/** SDK telemetry header name */
Expand Down
5 changes: 2 additions & 3 deletions ccip-sdk/src/evm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
keccak256,
toBeHex,
toBigInt,
zeroPadValue,
} from 'ethers'
import type { TypedContract } from 'ethers-abitype'
import { memoize } from 'micro-memoize'
Expand Down Expand Up @@ -85,6 +84,7 @@ import {
import {
decodeAddress,
decodeOnRampAddress,
encodeAddressToAny,
getAddressBytes,
getDataBytes,
getSomeBlockNumberBefore,
Expand Down Expand Up @@ -144,8 +144,7 @@ function toRateLimiterState(b: RateLimiterBucket): RateLimiterState {
// Addresses <32 bytes (EVM 20B, Aptos/Solana/Sui 32B) are zero-padded to 32 bytes;
// Addresses >32 bytes (e.g., TON 4+32=36B) are used as raw bytes without padding
function encodeAddressToEvm(address: BytesLike): string {
const bytes = getAddressBytes(address)
return bytes.length < 32 ? zeroPadValue(bytes, 32) : hexlify(bytes)
return hexlify(encodeAddressToAny(address))
}

/** typeguard for ethers Signer interface (used for `wallet`s) */
Expand Down
40 changes: 40 additions & 0 deletions ccip-sdk/src/execution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,46 @@ describe('calculateManualExecProof', () => {
assert.equal(result.proofFlagBits, 0n)
})

// https://api.ccip.chain.link/v2/messages/0xc9d521e2b4be8d995d7f9ffbde183e12d88ec93794d6b4329c23cb354db406a8/execution-inputs
it('should calculate manual execution proof for v1.6 Solana->TON', () => {
const merkleRoot = '0x050adeaa0cfe792abbd5e33a3ba6f2d9204052952d091f7624d1a2d23b771ad1'
const messageId = '0xc9d521e2b4be8d995d7f9ffbde183e12d88ec93794d6b4329c23cb354db406a8'
const messagesInBatch: CCIPMessage[] = [
{
data: '0x48656c6c6f',
nonce: 0n,
messageId,
sequenceNumber: 4n,
destChainSelector: 1399300952838017768n,
sourceChainSelector: 16423721717087811551n,
sender: '9NhaY2AXejCX3c4tXufzWuv52ZG7rjTJDeb1qSo9UV7S',
feeToken: 'So11111111111111111111111111111111111111112',
receiver: 'EQD4w5mxY0V7Szh2NsZ_BfWuMY6biF42HEjBz1-8_wRO-6gC',
extraArgs: '0x181dcf1040787d0100000000000000000000000001',
tokenAmounts: [],
feeValueJuels: 14388425000000000n,
feeTokenAmount: 1547524n,
allowOutOfOrderExecution: true,
gasLimit: 25000000n,
} as any,
]

const lane: Lane = {
sourceChainSelector: 16423721717087811551n,
destChainSelector: 1399300952838017768n,
onRamp: 'Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C',
version: CCIPVersion.V1_6,
}

const result = calculateManualExecProof(messagesInBatch, lane, messageId, merkleRoot, {
logger: console,
})

assert.equal(result.merkleRoot, merkleRoot)
assert.equal(result.proofs.length, 0)
assert.equal(result.proofFlagBits, 0n)
})

it('should calculate Aptos root correctly', () => {
// Test with actual Aptos message structure from requests.test.ts
const msgInfoString =
Expand Down
58 changes: 49 additions & 9 deletions ccip-sdk/src/extra-args.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,12 @@ describe('encodeExtraArgs', () => {
ChainFamily.TON,
)

assert.equal(
encoded,
EVMExtraArgsV2Tag + '8000000000000000000000000000000000000000000000000000000000030d4060',
)
assert.match(encoded, /^0xb5ee9c72/)
assert.deepEqual(decodeExtraArgs(encoded, ChainFamily.TON), {
_tag: 'EVMExtraArgsV2',
gasLimit: 400000n,
allowOutOfOrderExecution: true,
})
})

it('should encode EVMExtraArgsV2 (GenericExtraArgsV2) with allowOutOfOrderExecution false', () => {
Expand All @@ -98,10 +100,12 @@ describe('encodeExtraArgs', () => {
ChainFamily.TON,
)

assert.equal(
encoded,
EVMExtraArgsV2Tag + '800000000000000000000000000000000000000000000000000000000003d09020',
)
assert.match(encoded, /^0xb5ee9c72/)
assert.deepEqual(decodeExtraArgs(encoded, ChainFamily.TON), {
_tag: 'EVMExtraArgsV2',
gasLimit: 500000n,
allowOutOfOrderExecution: false,
})
})

it('should parse real Sepolia->TON message extraArgs', () => {
Expand Down Expand Up @@ -271,8 +275,44 @@ describe('parseExtraArgs', () => {
const original = { gasLimit: 400_000n, allowOutOfOrderExecution: true }
const encoded = encodeExtraArgs(original, ChainFamily.TON)
const decoded = decodeExtraArgs(encoded, ChainFamily.TON)
assert.match(encoded, /^0xb5ee9c72/)
assert.deepEqual(decoded, { ...original, _tag: 'EVMExtraArgsV2' })
})

it('should round-trip TON SVMExtraArgsV1', () => {
const original = {
computeUnits: 250_000n,
accountIsWritableBitmap: 3n,
allowOutOfOrderExecution: true,
tokenReceiver: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
accounts: [
'11111111111111111111111111111111',
'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL',
],
}
const encoded = encodeExtraArgs(original, ChainFamily.TON)
const decoded = decodeExtraArgs(encoded, ChainFamily.TON)

assert.match(encoded, /^0xb5ee9c72/)
assert.deepEqual(decoded, { ...original, _tag: 'SVMExtraArgsV1' })
})

it('should round-trip TON SuiExtraArgsV1', () => {
const original = {
gasLimit: 350_000n,
allowOutOfOrderExecution: false,
tokenReceiver: '0x1111111111111111111111111111111111111111111111111111111111111111',
receiverObjectIds: [
'0x2222222222222222222222222222222222222222222222222222222222222222',
'0x3333333333333333333333333333333333333333333333333333333333333333',
],
}
const encoded = encodeExtraArgs(original, ChainFamily.TON)
const decoded = decodeExtraArgs(encoded, ChainFamily.TON)

assert.match(encoded, /^0xb5ee9c72/)
assert.deepEqual(decoded, { ...original, _tag: 'SuiExtraArgsV1' })
})
})

describe('encoding format differences', () => {
Expand Down Expand Up @@ -304,7 +344,7 @@ describe('parseExtraArgs', () => {
const tonEncoded = encodeExtraArgs(args, ChainFamily.TON)

assert.equal(evmEncoded.substring(0, 10), EVMExtraArgsV2Tag)
assert.equal(tonEncoded.substring(0, 10), EVMExtraArgsV2Tag)
assert.equal(tonEncoded.substring(0, 10), '0xb5ee9c72') // TON's BOC encoding marker
assert.notEqual(evmEncoded, tonEncoded)
})
})
Expand Down
5 changes: 2 additions & 3 deletions ccip-sdk/src/solana/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
PublicKey,
} from '@solana/web3.js'
import BN from 'bn.js'
import { zeroPadValue } from 'ethers'

import { SolanaChain } from './index.ts'
import { CCIPError } from '../errors/CCIPError.ts'
Expand All @@ -22,7 +21,7 @@
CCIPTokenAmountInvalidError,
} from '../errors/index.ts'
import { type AnyMessage, type WithLogger, ChainFamily } from '../types.ts'
import { bytesToBuffer, toLeArray } from '../utils.ts'
import { bytesToBuffer, toLeArray, encodeAddressToAny } from '../utils.ts'

Check warning on line 24 in ccip-sdk/src/solana/send.ts

View workflow job for this annotation

GitHub Actions / build-and-test

`encodeAddressToAny` import should occur before import of `toLeArray`
import { IDL as CCIP_ROUTER_IDL } from './idl/1.6.0/CCIP_ROUTER.ts'
import type { UnsignedSolanaTx } from './types.ts'
import { resolveATA, simulateTransaction, simulationProvider } from './utils.ts'
Expand All @@ -31,7 +30,7 @@
const feeTokenPubkey = message.feeToken ? new PublicKey(message.feeToken) : PublicKey.default

const svmMessage: IdlTypes<typeof CCIP_ROUTER_IDL>['SVM2AnyMessage'] = {
receiver: bytesToBuffer(zeroPadValue(message.receiver, 32)),
receiver: encodeAddressToAny(message.receiver),
data: bytesToBuffer(message.data || '0x'),
tokenAmounts: (message.tokenAmounts || []).map((ta) => {
if (!ta.token || ta.amount < 0n) {
Expand Down
Loading
Loading