Skip to content
Open
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
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ jobs:
- name: Verify anvil is available
run: anvil --version

- name: Install Surfpool v1.1.2 (for SVM fork tests)
# >= 1.5.0 forks as Agave 4.x (solana-core 4.1.2) and accepts version-1
# transactions, which the SDK sends when a tx exceeds the v0 packet limit
- name: Install Surfpool v1.5.0 (for SVM fork tests)
run: |
curl -sSL https://github.com/solana-foundation/surfpool/releases/download/v1.1.2/surfpool-linux-x64.tar.gz \
curl -sSL https://github.com/solana-foundation/surfpool/releases/download/v1.5.0/surfpool-linux-x64.tar.gz \
| tar xz -C /usr/local/bin

- name: Verify surfpool is available
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- Solana: supports reading and sending Version-1 transactions (Agave 4.x devnet and later), up to 4096 bytes per message
- Tests: the whole suite runs as one parallel `node --test` invocation — networked e2e/integration suites moved to disjoint low-activity lanes/fixtures with per-network endpoint sets configurable via `RPC_*` env vars (one per network, comma-separated lists allowed, wired to CI secrets), so suites never contend on a rate-limited endpoint and the full run finishes in ~5min
- Aptos and Sui now support detecting execution failures — bundled Sui fixes: deep-history `getLogs` walks ascending checkpoint slices instead of paging from the tip, empty `getOwnedObjects` pointer lookups are memoized instead of retried for ~30s, and `offRamp` receipt filters no longer drop successful Aptos/Sui receipts

Expand Down
2 changes: 1 addition & 1 deletion ccip-api-ref/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.10.2",
"@docusaurus/types": "^3.10.2",
"@types/react-dom": "^19.2.4",
"@types/react-dom": "^19.2.5",
"@typescript/native": "npm:typescript@7.0.2",
"docusaurus-plugin-typedoc": "^1.4.2",
"typedoc": "^0.28.20",
Expand Down
4 changes: 2 additions & 2 deletions ccip-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@
"@ledgerhq/hw-app-aptos": "6.37.0",
"@ledgerhq/hw-app-solana": "7.9.0",
"@ledgerhq/hw-transport-node-hid": "6.32.0",
"@mysten/sui": "^2.23.2",
"@solana/web3.js": "^1.98.4",
"@mysten/sui": "^2.26.2",
"@solana/web3.js": "^1.99.0",
"@ton-community/ton-ledger": "^7.3.0",
"@ton/crypto": "^3.3.0",
"@ton/ton": "^16.3.0",
Expand Down
3 changes: 2 additions & 1 deletion ccip-cli/src/providers/solana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import HIDTransport from '@ledgerhq/hw-transport-node-hid'
import {
type Message,
type MessageV0,
type MessageV1,
type VersionedTransaction,
Keypair,
PublicKey,
Expand Down Expand Up @@ -72,7 +73,7 @@ export class LedgerSolanaWallet {
this.logger.debug('Ledger: Request to sign message from', this.publicKey.toBase58())
// serializeMessage on v0, serialize on v1

let msg: Message | MessageV0
let msg: Message | MessageV0 | MessageV1
if (tx instanceof Transaction) {
msg = tx.compileMessage()
} else {
Expand Down
8 changes: 4 additions & 4 deletions ccip-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,16 @@
"ethers-abitype": "1.0.3",
"prool": "^0.2.14",
"typescript": "7.0.2",
"viem": "^2.55.13"
"viem": "^2.55.19"
},
"dependencies": {
"@aptos-labs/ts-sdk": "^7.3.0",
"@coral-xyz/anchor": "^0.29.0",
"@mysten/bcs": "^2.1.0",
"@mysten/sui": "^2.23.2",
"@mysten/bcs": "^2.1.1",
"@mysten/sui": "^2.26.2",
"@noble/hashes": "^2.3.0",
"@solana/spl-token": "0.4.15",
"@solana/web3.js": "^1.98.4",
"@solana/web3.js": "^1.99.0",
"@ton/core": "0.63.1",
"@ton/ton": "^16.3.0",
"abitype": "1.3.0",
Expand Down
1 change: 1 addition & 0 deletions ccip-sdk/src/errors/codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const CCIPErrorCode = {
BLOCK_TIME_NOT_FOUND: 'BLOCK_TIME_NOT_FOUND',
BLOCK_BEFORE_TIMESTAMP_NOT_FOUND: 'BLOCK_BEFORE_TIMESTAMP_NOT_FOUND',
TRANSACTION_NOT_FINALIZED: 'TRANSACTION_NOT_FINALIZED',
TRANSACTION_TOO_LARGE: 'TRANSACTION_TOO_LARGE',

// CCIP Message
MESSAGE_INVALID: 'MESSAGE_INVALID',
Expand Down
6 changes: 5 additions & 1 deletion ccip-sdk/src/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ export {
} from './specialized.ts'

// Specialized errors - Block & Transaction
export { CCIPBlockNotFoundError, CCIPTransactionNotFoundError } from './specialized.ts'
export {
CCIPBlockNotFoundError,
CCIPTransactionNotFoundError,
CCIPTransactionTooLargeError,
} from './specialized.ts'

// Specialized errors - Logs
export {
Expand Down
2 changes: 2 additions & 0 deletions ccip-sdk/src/errors/recovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export const DEFAULT_RECOVERY_HINTS: Partial<Record<CCIPErrorCode, string>> = {
BLOCK_TIME_NOT_FOUND: 'Wait and retry. Block time data may not be available yet.',
BLOCK_BEFORE_TIMESTAMP_NOT_FOUND: 'No block exists before the specified timestamp.',
TRANSACTION_NOT_FINALIZED: 'Wait for transaction finality.',
TRANSACTION_TOO_LARGE:
'Transaction exceeds its version wire size limit (1232 bytes for v0, 4096 for v1). Reduce the message data or split into smaller transactions.',

MESSAGE_INVALID: 'Verify the message format matches the expected CCIP message structure.',
MESSAGE_DECODE_FAILED:
Expand Down
28 changes: 28 additions & 0 deletions ccip-sdk/src/errors/specialized.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,34 @@ export class CCIPTransactionNotFoundError extends CCIPError {
}
}

/**
* Thrown when a transaction exceeds the wire size limits of its version
* (1232 bytes for legacy/v0, 4096 bytes for v1) or the account/instruction
* capacity of its message format.
*
* @example
* ```typescript
* try {
* await chain.execute(input)
* } catch (error) {
* if (error instanceof CCIPTransactionTooLargeError) {
* console.log(`Transaction needs ${error.context.wireBytes} bytes`)
* }
* }
* ```
*/
export class CCIPTransactionTooLargeError extends CCIPError {
override readonly name = 'CCIPTransactionTooLargeError'
/** Creates a transaction too large error. */
constructor(message: string, options?: CCIPErrorOptions) {
super(CCIPErrorCode.TRANSACTION_TOO_LARGE, message, {
...options,
isTransient: false,
context: { ...options?.context },
})
}
}

// CCIP Message

/**
Expand Down
17 changes: 13 additions & 4 deletions ccip-sdk/src/evm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ import {
getAddressBytes,
getBlockNumberAtOrAfter,
getDataBytes,
linkAbortSignals,
parseTypeAndVersion,
} from '../utils.ts'
import type Token_ABI from './abi/BurnMintERC677Token.ts'
Expand Down Expand Up @@ -566,21 +567,29 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
// 90s comfortably exceeds any legitimate slow call (a chunked
// eth_getLogs under active pacing).
const timeoutSignal = AbortSignal.timeout(90_000)
let requestSignal: AbortSignal = timeoutSignal
// The cancel bridge and the 90s bound are followed through a LINK, not
// composed into a fresh AbortSignal.any composite: a composite over a
// kTimeout source is never listened to directly (undici attaches to the
// downstream merge), so its following never activates and it pins in
// Node's gcPersistentSignals for the process's lifetime — one composite
// per RPC request. The `using` link detaches on return instead (see
// linkAbortSignals).
let linkSource: AbortSignal | undefined
if (signal) {
const cancel = new AbortController()
try {
signal.addListener(() => cancel.abort())
requestSignal = AbortSignal.any([cancel.signal, timeoutSignal])
linkSource = cancel.signal
} catch {
requestSignal = AbortSignal.abort() // already cancelled by ethers
linkSource = AbortSignal.abort() // already cancelled by ethers
}
}
using link = linkSource ? linkAbortSignals([linkSource, timeoutSignal]) : null
const resp = await fetchFn(r.url, {
method: r.method || 'POST',
headers: Object.fromEntries(Object.entries(r.headers).map(([k, v]) => [k, String(v)])),
body: r.body ?? undefined,
signal: requestSignal,
signal: link?.signal ?? timeoutSignal,
})
const headers: Record<string, string> = {}
resp.headers.forEach((v, k) => {
Expand Down
Loading
Loading