@chainlink/ccip-sdk 0.0.0 → 0.90.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +109 -0
- package/dist/aptos/exec.d.ts +18 -0
- package/dist/aptos/exec.d.ts.map +1 -0
- package/dist/aptos/exec.js +55 -0
- package/dist/aptos/exec.js.map +1 -0
- package/dist/aptos/hasher.d.ts +11 -0
- package/dist/aptos/hasher.d.ts.map +1 -0
- package/dist/aptos/hasher.js +62 -0
- package/dist/aptos/hasher.js.map +1 -0
- package/dist/aptos/index.d.ts +92 -0
- package/dist/aptos/index.d.ts.map +1 -0
- package/dist/aptos/index.js +482 -0
- package/dist/aptos/index.js.map +1 -0
- package/dist/aptos/logs.d.ts +9 -0
- package/dist/aptos/logs.d.ts.map +1 -0
- package/dist/aptos/logs.js +167 -0
- package/dist/aptos/logs.js.map +1 -0
- package/dist/aptos/send.d.ts +11 -0
- package/dist/aptos/send.d.ts.map +1 -0
- package/dist/aptos/send.js +78 -0
- package/dist/aptos/send.js.map +1 -0
- package/dist/aptos/token.d.ts +4 -0
- package/dist/aptos/token.d.ts.map +1 -0
- package/dist/aptos/token.js +134 -0
- package/dist/aptos/token.js.map +1 -0
- package/dist/aptos/types.d.ts +78 -0
- package/dist/aptos/types.d.ts.map +1 -0
- package/dist/aptos/types.js +60 -0
- package/dist/aptos/types.js.map +1 -0
- package/dist/aptos/utils.d.ts +12 -0
- package/dist/aptos/utils.d.ts.map +1 -0
- package/dist/aptos/utils.js +15 -0
- package/dist/aptos/utils.js.map +1 -0
- package/dist/chain.d.ts +344 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +41 -0
- package/dist/chain.js.map +1 -0
- package/dist/commits.d.ts +25 -0
- package/dist/commits.d.ts.map +1 -0
- package/dist/commits.js +29 -0
- package/dist/commits.js.map +1 -0
- package/dist/evm/abi/BurnMintERC677Token.d.ts +602 -0
- package/dist/evm/abi/BurnMintERC677Token.d.ts.map +1 -0
- package/dist/evm/abi/BurnMintERC677Token.js +488 -0
- package/dist/evm/abi/BurnMintERC677Token.js.map +1 -0
- package/dist/evm/abi/CommitStore_1_2.d.ts +688 -0
- package/dist/evm/abi/CommitStore_1_2.d.ts.map +1 -0
- package/dist/evm/abi/CommitStore_1_2.js +638 -0
- package/dist/evm/abi/CommitStore_1_2.js.map +1 -0
- package/dist/evm/abi/CommitStore_1_5.d.ts +708 -0
- package/dist/evm/abi/CommitStore_1_5.d.ts.map +1 -0
- package/dist/evm/abi/CommitStore_1_5.js +675 -0
- package/dist/evm/abi/CommitStore_1_5.js.map +1 -0
- package/dist/evm/abi/FeeQuoter_1_6.d.ts +1770 -0
- package/dist/evm/abi/FeeQuoter_1_6.d.ts.map +1 -0
- package/dist/evm/abi/FeeQuoter_1_6.js +1904 -0
- package/dist/evm/abi/FeeQuoter_1_6.js.map +1 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_5.d.ts +1116 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_5.d.ts.map +1 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_5.js +1096 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_5.js.map +1 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_5_1.d.ts +1306 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_5_1.d.ts.map +1 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_5_1.js +1278 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_5_1.js.map +1 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_6_1.d.ts +1290 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_6_1.d.ts.map +1 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_6_1.js +1288 -0
- package/dist/evm/abi/LockReleaseTokenPool_1_6_1.js.map +1 -0
- package/dist/evm/abi/OffRamp_1_2.d.ts +1217 -0
- package/dist/evm/abi/OffRamp_1_2.d.ts.map +1 -0
- package/dist/evm/abi/OffRamp_1_2.js +1204 -0
- package/dist/evm/abi/OffRamp_1_2.js.map +1 -0
- package/dist/evm/abi/OffRamp_1_5.d.ts +1271 -0
- package/dist/evm/abi/OffRamp_1_5.d.ts.map +1 -0
- package/dist/evm/abi/OffRamp_1_5.js +1273 -0
- package/dist/evm/abi/OffRamp_1_5.js.map +1 -0
- package/dist/evm/abi/OffRamp_1_6.d.ts +1472 -0
- package/dist/evm/abi/OffRamp_1_6.d.ts.map +1 -0
- package/dist/evm/abi/OffRamp_1_6.js +1529 -0
- package/dist/evm/abi/OffRamp_1_6.js.map +1 -0
- package/dist/evm/abi/OnRamp_1_2.d.ts +1391 -0
- package/dist/evm/abi/OnRamp_1_2.d.ts.map +1 -0
- package/dist/evm/abi/OnRamp_1_2.js +1343 -0
- package/dist/evm/abi/OnRamp_1_2.js.map +1 -0
- package/dist/evm/abi/OnRamp_1_5.d.ts +1443 -0
- package/dist/evm/abi/OnRamp_1_5.d.ts.map +1 -0
- package/dist/evm/abi/OnRamp_1_5.js +1427 -0
- package/dist/evm/abi/OnRamp_1_5.js.map +1 -0
- package/dist/evm/abi/OnRamp_1_6.d.ts +796 -0
- package/dist/evm/abi/OnRamp_1_6.d.ts.map +1 -0
- package/dist/evm/abi/OnRamp_1_6.js +880 -0
- package/dist/evm/abi/OnRamp_1_6.js.map +1 -0
- package/dist/evm/abi/Router.d.ts +541 -0
- package/dist/evm/abi/Router.d.ts.map +1 -0
- package/dist/evm/abi/Router.js +508 -0
- package/dist/evm/abi/Router.js.map +1 -0
- package/dist/evm/abi/TokenAdminRegistry_1_5.d.ts +373 -0
- package/dist/evm/abi/TokenAdminRegistry_1_5.d.ts.map +1 -0
- package/dist/evm/abi/TokenAdminRegistry_1_5.js +333 -0
- package/dist/evm/abi/TokenAdminRegistry_1_5.js.map +1 -0
- package/dist/evm/const.d.ts +27 -0
- package/dist/evm/const.d.ts.map +1 -0
- package/dist/evm/const.js +63 -0
- package/dist/evm/const.js.map +1 -0
- package/dist/evm/errors.d.ts +36 -0
- package/dist/evm/errors.d.ts.map +1 -0
- package/dist/evm/errors.js +192 -0
- package/dist/evm/errors.js.map +1 -0
- package/dist/evm/hasher.d.ts +5 -0
- package/dist/evm/hasher.d.ts.map +1 -0
- package/dist/evm/hasher.js +116 -0
- package/dist/evm/hasher.js.map +1 -0
- package/dist/evm/index.d.ts +121 -0
- package/dist/evm/index.d.ts.map +1 -0
- package/dist/evm/index.js +904 -0
- package/dist/evm/index.js.map +1 -0
- package/dist/evm/messages.d.ts +35 -0
- package/dist/evm/messages.d.ts.map +1 -0
- package/dist/evm/messages.js +11 -0
- package/dist/evm/messages.js.map +1 -0
- package/dist/evm/offchain.d.ts +16 -0
- package/dist/evm/offchain.d.ts.map +1 -0
- package/dist/evm/offchain.js +142 -0
- package/dist/evm/offchain.js.map +1 -0
- package/dist/execution.d.ts +80 -0
- package/dist/execution.d.ts.map +1 -0
- package/dist/execution.js +91 -0
- package/dist/execution.js.map +1 -0
- package/dist/extra-args.d.ts +45 -0
- package/dist/extra-args.d.ts.map +1 -0
- package/dist/extra-args.js +44 -0
- package/dist/extra-args.js.map +1 -0
- package/dist/gas.d.ts +27 -0
- package/dist/gas.d.ts.map +1 -0
- package/dist/gas.js +80 -0
- package/dist/gas.js.map +1 -0
- package/dist/hasher/common.d.ts +12 -0
- package/dist/hasher/common.d.ts.map +1 -0
- package/dist/hasher/common.js +19 -0
- package/dist/hasher/common.js.map +1 -0
- package/dist/hasher/hasher.d.ts +4 -0
- package/dist/hasher/hasher.d.ts.map +1 -0
- package/dist/hasher/hasher.js +11 -0
- package/dist/hasher/hasher.js.map +1 -0
- package/dist/hasher/index.d.ts +4 -0
- package/dist/hasher/index.d.ts.map +1 -0
- package/dist/hasher/index.js +4 -0
- package/dist/hasher/index.js.map +1 -0
- package/dist/hasher/merklemulti.d.ts +58 -0
- package/dist/hasher/merklemulti.d.ts.map +1 -0
- package/dist/hasher/merklemulti.js +257 -0
- package/dist/hasher/merklemulti.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/offchain.d.ts +20 -0
- package/dist/offchain.d.ts.map +1 -0
- package/dist/offchain.js +59 -0
- package/dist/offchain.js.map +1 -0
- package/dist/requests.d.ts +48 -0
- package/dist/requests.d.ts.map +1 -0
- package/dist/requests.js +286 -0
- package/dist/requests.js.map +1 -0
- package/dist/selectors.d.ts +9 -0
- package/dist/selectors.d.ts.map +1 -0
- package/dist/selectors.js +1330 -0
- package/dist/selectors.js.map +1 -0
- package/dist/solana/cleanup.d.ts +15 -0
- package/dist/solana/cleanup.d.ts.map +1 -0
- package/dist/solana/cleanup.js +159 -0
- package/dist/solana/cleanup.js.map +1 -0
- package/dist/solana/exec.d.ts +15 -0
- package/dist/solana/exec.d.ts.map +1 -0
- package/dist/solana/exec.js +417 -0
- package/dist/solana/exec.js.map +1 -0
- package/dist/solana/hasher.d.ts +4 -0
- package/dist/solana/hasher.d.ts.map +1 -0
- package/dist/solana/hasher.js +81 -0
- package/dist/solana/hasher.js.map +1 -0
- package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.d.ts +866 -0
- package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.d.ts.map +1 -0
- package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.js +866 -0
- package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.js.map +1 -0
- package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.d.ts +949 -0
- package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.d.ts.map +1 -0
- package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.js +949 -0
- package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.js.map +1 -0
- package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.d.ts +1374 -0
- package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.d.ts.map +1 -0
- package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.js +1374 -0
- package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.js.map +1 -0
- package/dist/solana/idl/1.6.0/CCIP_COMMON.d.ts +104 -0
- package/dist/solana/idl/1.6.0/CCIP_COMMON.d.ts.map +1 -0
- package/dist/solana/idl/1.6.0/CCIP_COMMON.js +104 -0
- package/dist/solana/idl/1.6.0/CCIP_COMMON.js.map +1 -0
- package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.d.ts +2746 -0
- package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.d.ts.map +1 -0
- package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.js +2746 -0
- package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.js.map +1 -0
- package/dist/solana/idl/1.6.0/CCIP_ROUTER.d.ts +2332 -0
- package/dist/solana/idl/1.6.0/CCIP_ROUTER.d.ts.map +1 -0
- package/dist/solana/idl/1.6.0/CCIP_ROUTER.js +2332 -0
- package/dist/solana/idl/1.6.0/CCIP_ROUTER.js.map +1 -0
- package/dist/solana/index.d.ts +205 -0
- package/dist/solana/index.d.ts.map +1 -0
- package/dist/solana/index.js +1085 -0
- package/dist/solana/index.js.map +1 -0
- package/dist/solana/offchain.d.ts +31 -0
- package/dist/solana/offchain.d.ts.map +1 -0
- package/dist/solana/offchain.js +152 -0
- package/dist/solana/offchain.js.map +1 -0
- package/dist/solana/patchBorsh.d.ts +2 -0
- package/dist/solana/patchBorsh.d.ts.map +1 -0
- package/dist/solana/patchBorsh.js +60 -0
- package/dist/solana/patchBorsh.js.map +1 -0
- package/dist/solana/send.d.ts +14 -0
- package/dist/solana/send.d.ts.map +1 -0
- package/dist/solana/send.js +272 -0
- package/dist/solana/send.js.map +1 -0
- package/dist/solana/types.d.ts +4 -0
- package/dist/solana/types.d.ts.map +1 -0
- package/dist/solana/types.js +2 -0
- package/dist/solana/types.js.map +1 -0
- package/dist/solana/utils.d.ts +58 -0
- package/dist/solana/utils.d.ts.map +1 -0
- package/dist/solana/utils.js +211 -0
- package/dist/solana/utils.js.map +1 -0
- package/dist/sui/hasher.d.ts +12 -0
- package/dist/sui/hasher.d.ts.map +1 -0
- package/dist/sui/hasher.js +63 -0
- package/dist/sui/hasher.js.map +1 -0
- package/dist/sui/index.d.ts +72 -0
- package/dist/sui/index.d.ts.map +1 -0
- package/dist/sui/index.js +128 -0
- package/dist/sui/index.js.map +1 -0
- package/dist/sui/types.d.ts +17 -0
- package/dist/sui/types.d.ts.map +1 -0
- package/dist/sui/types.js +17 -0
- package/dist/sui/types.js.map +1 -0
- package/dist/supported-chains.d.ts +5 -0
- package/dist/supported-chains.d.ts.map +1 -0
- package/dist/supported-chains.js +3 -0
- package/dist/supported-chains.js.map +1 -0
- package/dist/types.d.ts +118 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +117 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +336 -0
- package/dist/utils.js.map +1 -0
- package/package.json +66 -8
- package/src/aptos/exec.ts +69 -0
- package/src/aptos/hasher.ts +92 -0
- package/src/aptos/index.ts +660 -0
- package/src/aptos/logs.ts +210 -0
- package/src/aptos/send.ts +120 -0
- package/src/aptos/token.ts +150 -0
- package/src/aptos/types.ts +85 -0
- package/src/aptos/utils.ts +24 -0
- package/src/chain.ts +398 -0
- package/src/commits.ts +44 -0
- package/src/evm/abi/BurnMintERC677Token.ts +487 -0
- package/src/evm/abi/CommitStore_1_2.ts +637 -0
- package/src/evm/abi/CommitStore_1_5.ts +674 -0
- package/src/evm/abi/FeeQuoter_1_6.ts +1903 -0
- package/src/evm/abi/LockReleaseTokenPool_1_5.ts +1095 -0
- package/src/evm/abi/LockReleaseTokenPool_1_5_1.ts +1277 -0
- package/src/evm/abi/LockReleaseTokenPool_1_6_1.ts +1287 -0
- package/src/evm/abi/OffRamp_1_2.ts +1203 -0
- package/src/evm/abi/OffRamp_1_5.ts +1272 -0
- package/src/evm/abi/OffRamp_1_6.ts +1528 -0
- package/src/evm/abi/OnRamp_1_2.ts +1342 -0
- package/src/evm/abi/OnRamp_1_5.ts +1426 -0
- package/src/evm/abi/OnRamp_1_6.ts +879 -0
- package/src/evm/abi/Router.ts +507 -0
- package/src/evm/abi/TokenAdminRegistry_1_5.ts +332 -0
- package/src/evm/const.ts +69 -0
- package/src/evm/errors.ts +212 -0
- package/src/evm/hasher.ts +166 -0
- package/src/evm/index.ts +1262 -0
- package/src/evm/messages.ts +73 -0
- package/src/evm/offchain.ts +189 -0
- package/src/execution.ts +131 -0
- package/src/extra-args.ts +71 -0
- package/src/gas.ts +135 -0
- package/src/hasher/common.ts +23 -0
- package/src/hasher/hasher.ts +12 -0
- package/src/hasher/index.ts +3 -0
- package/src/hasher/merklemulti.ts +309 -0
- package/src/index.ts +51 -0
- package/src/offchain.ts +86 -0
- package/src/requests.ts +339 -0
- package/src/selectors.ts +1340 -0
- package/src/solana/cleanup.ts +216 -0
- package/src/solana/exec.ts +645 -0
- package/src/solana/hasher.ts +104 -0
- package/src/solana/idl/1.6.0/BASE_TOKEN_POOL.ts +1734 -0
- package/src/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.ts +1900 -0
- package/src/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.ts +2750 -0
- package/src/solana/idl/1.6.0/CCIP_COMMON.ts +210 -0
- package/src/solana/idl/1.6.0/CCIP_OFFRAMP.ts +5494 -0
- package/src/solana/idl/1.6.0/CCIP_ROUTER.ts +4671 -0
- package/src/solana/index.ts +1454 -0
- package/src/solana/offchain.ts +209 -0
- package/src/solana/patchBorsh.ts +67 -0
- package/src/solana/send.ts +436 -0
- package/src/solana/types.ts +6 -0
- package/src/solana/utils.ts +272 -0
- package/src/sui/hasher.ts +90 -0
- package/src/sui/index.ts +198 -0
- package/src/sui/types.ts +22 -0
- package/src/supported-chains.ts +4 -0
- package/src/types.ts +153 -0
- package/src/utils.ts +405 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
import { type AnchorProvider, type IdlTypes, Program } from '@coral-xyz/anchor'
|
|
2
|
+
import {
|
|
3
|
+
type AccountMeta,
|
|
4
|
+
type Transaction,
|
|
5
|
+
type TransactionInstruction,
|
|
6
|
+
AddressLookupTableAccount,
|
|
7
|
+
AddressLookupTableProgram,
|
|
8
|
+
ComputeBudgetProgram,
|
|
9
|
+
PublicKey,
|
|
10
|
+
SendTransactionError,
|
|
11
|
+
SystemProgram,
|
|
12
|
+
TransactionExpiredBlockheightExceededError,
|
|
13
|
+
TransactionMessage,
|
|
14
|
+
VersionedTransaction,
|
|
15
|
+
} from '@solana/web3.js'
|
|
16
|
+
import BN from 'bn.js'
|
|
17
|
+
import { hexlify } from 'ethers'
|
|
18
|
+
|
|
19
|
+
import type { ExecutionReport } from '../types.ts'
|
|
20
|
+
import { IDL as CCIP_OFFRAMP_IDL } from './idl/1.6.0/CCIP_OFFRAMP.ts'
|
|
21
|
+
import { encodeSolanaOffchainTokenData } from './offchain.ts'
|
|
22
|
+
import type { CCIPMessage_V1_6_Solana } from './types.ts'
|
|
23
|
+
import type { ChainTransaction } from '../chain.ts'
|
|
24
|
+
import { getDataBytes, sleep, toLeArray } from '../utils.ts'
|
|
25
|
+
import { bytesToBuffer, simulateTransaction, simulationProvider } from './utils.ts'
|
|
26
|
+
import './patchBorsh.ts'
|
|
27
|
+
|
|
28
|
+
type ExecStepTx = readonly [reason: string, transactions: VersionedTransaction]
|
|
29
|
+
|
|
30
|
+
type ExecAlt = {
|
|
31
|
+
addressLookupTableAccount: AddressLookupTableAccount
|
|
32
|
+
initialTxs: ExecStepTx[]
|
|
33
|
+
finalTxs: ExecStepTx[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function executeReport({
|
|
37
|
+
offrampProgram,
|
|
38
|
+
execReport,
|
|
39
|
+
...opts
|
|
40
|
+
}: {
|
|
41
|
+
offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>
|
|
42
|
+
execReport: ExecutionReport<CCIPMessage_V1_6_Solana>
|
|
43
|
+
gasLimit?: number
|
|
44
|
+
forceLookupTable?: boolean
|
|
45
|
+
forceBuffer?: boolean
|
|
46
|
+
clearLeftoverAccounts?: boolean
|
|
47
|
+
}): Promise<Pick<ChainTransaction, 'hash'>> {
|
|
48
|
+
const provider = offrampProgram.provider as AnchorProvider
|
|
49
|
+
const wallet = provider.wallet
|
|
50
|
+
const connection = provider.connection
|
|
51
|
+
|
|
52
|
+
const execTxs = await buildExecTxToSolana(offrampProgram, execReport, opts?.gasLimit, opts)
|
|
53
|
+
|
|
54
|
+
let execTxSignature: string, signature: string
|
|
55
|
+
for (const [i, [reason, transaction]] of execTxs.entries()) {
|
|
56
|
+
// Refresh the blockhash for each transaction, as the blockhash is only valid for a short time
|
|
57
|
+
// and we spend a lot of time waiting for finalization of the previous transactions.
|
|
58
|
+
transaction.message.recentBlockhash = (await connection.getLatestBlockhash()).blockhash
|
|
59
|
+
|
|
60
|
+
const signed = await wallet.signTransaction(transaction)
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
signature = await connection.sendTransaction(signed)
|
|
64
|
+
|
|
65
|
+
if (reason === 'exec') execTxSignature = signature
|
|
66
|
+
} catch (e) {
|
|
67
|
+
if (
|
|
68
|
+
e instanceof SendTransactionError &&
|
|
69
|
+
e.logs?.some((log) =>
|
|
70
|
+
log.includes('Error Code: ExecutionReportBufferAlreadyContainsChunk.'),
|
|
71
|
+
)
|
|
72
|
+
) {
|
|
73
|
+
console.warn(
|
|
74
|
+
`Skipping tx ${i + 1} of ${execTxs.length} because a chunk is already in the buffer.`,
|
|
75
|
+
)
|
|
76
|
+
continue
|
|
77
|
+
} else {
|
|
78
|
+
throw e
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.debug(`Confirming tx #${i + 1} of ${execTxs.length}: ${signature} (${reason})...`)
|
|
83
|
+
for (let currentAttempt = 0; ; currentAttempt++) {
|
|
84
|
+
try {
|
|
85
|
+
const latestBlockhash = await connection.getLatestBlockhash()
|
|
86
|
+
await connection.confirmTransaction(
|
|
87
|
+
{
|
|
88
|
+
signature,
|
|
89
|
+
blockhash: latestBlockhash.blockhash,
|
|
90
|
+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
|
91
|
+
},
|
|
92
|
+
'confirmed',
|
|
93
|
+
)
|
|
94
|
+
break
|
|
95
|
+
} catch (e) {
|
|
96
|
+
if (currentAttempt < 5 && e instanceof TransactionExpiredBlockheightExceededError) {
|
|
97
|
+
await sleep(1000)
|
|
98
|
+
} else {
|
|
99
|
+
throw e
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { hash: execTxSignature! }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function buildExecTxToSolana(
|
|
109
|
+
offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>,
|
|
110
|
+
execReport: ExecutionReport<CCIPMessage_V1_6_Solana>,
|
|
111
|
+
computeUnitsOverride: number | undefined,
|
|
112
|
+
opts?: { forceLookupTable?: boolean; forceBuffer?: boolean; clearLeftoverAccounts?: boolean },
|
|
113
|
+
): Promise<ExecStepTx[]> {
|
|
114
|
+
const provider = offrampProgram.provider as AnchorProvider
|
|
115
|
+
offrampProgram = new Program(CCIP_OFFRAMP_IDL, offrampProgram.programId, provider)
|
|
116
|
+
const payerAddress = provider.wallet.publicKey
|
|
117
|
+
|
|
118
|
+
let bufferId
|
|
119
|
+
if (opts?.forceBuffer) {
|
|
120
|
+
// Use messageId for bufferId. This is arbitrary, but easy to track.
|
|
121
|
+
bufferId = bytesToBuffer(execReport.message.header.messageId)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const {
|
|
125
|
+
executionReport: preparedReport,
|
|
126
|
+
tokenIndexes,
|
|
127
|
+
accounts,
|
|
128
|
+
addressLookupTables,
|
|
129
|
+
} = await getManuallyExecuteInputs({
|
|
130
|
+
execReport,
|
|
131
|
+
offrampProgram,
|
|
132
|
+
transmitter: payerAddress.toBase58(),
|
|
133
|
+
bufferId,
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const addressLookupTableAccounts = await Promise.all(
|
|
137
|
+
addressLookupTables.map(async (acc) => {
|
|
138
|
+
const lookupTableAccountInfo = await provider.connection.getAddressLookupTable(acc)
|
|
139
|
+
|
|
140
|
+
if (!lookupTableAccountInfo.value) {
|
|
141
|
+
throw new Error(`Lookup table account not found: ${acc.toBase58()}`)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return lookupTableAccountInfo.value
|
|
145
|
+
}),
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
let serializedReport = offrampProgram.coder.types.encode(
|
|
149
|
+
'ExecutionReportSingleChain',
|
|
150
|
+
preparedReport,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
const { blockhash: recentBlockhash } = await provider.connection.getLatestBlockhash()
|
|
154
|
+
|
|
155
|
+
let alt
|
|
156
|
+
if (opts?.forceLookupTable) {
|
|
157
|
+
alt = await buildLookupTableTxs(provider, accounts)
|
|
158
|
+
addressLookupTableAccounts.push(alt.addressLookupTableAccount)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const transactions: ExecStepTx[] = []
|
|
162
|
+
if (bufferId) {
|
|
163
|
+
console.log(`Execute report will be pre-buffered through the offramp. This may take some time.`)
|
|
164
|
+
transactions.push(
|
|
165
|
+
...(await bufferedTransactionData(
|
|
166
|
+
offrampProgram,
|
|
167
|
+
serializedReport,
|
|
168
|
+
recentBlockhash,
|
|
169
|
+
bufferId,
|
|
170
|
+
opts,
|
|
171
|
+
)),
|
|
172
|
+
)
|
|
173
|
+
serializedReport = Buffer.from([]) // clear 1st param to manuallyExecute method if buffered
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const execTx = await offrampProgram.methods
|
|
177
|
+
.manuallyExecute(serializedReport, tokenIndexes)
|
|
178
|
+
.accounts({
|
|
179
|
+
config: accounts[0].pubkey,
|
|
180
|
+
referenceAddresses: accounts[1].pubkey,
|
|
181
|
+
sourceChain: accounts[2].pubkey,
|
|
182
|
+
commitReport: accounts[3].pubkey,
|
|
183
|
+
offramp: accounts[4].pubkey,
|
|
184
|
+
allowedOfframp: accounts[5].pubkey,
|
|
185
|
+
authority: accounts[6].pubkey,
|
|
186
|
+
systemProgram: accounts[7].pubkey,
|
|
187
|
+
sysvarInstructions: accounts[8].pubkey,
|
|
188
|
+
rmnRemote: accounts[9].pubkey,
|
|
189
|
+
rmnRemoteCurses: accounts[10].pubkey,
|
|
190
|
+
rmnRemoteConfig: accounts[11].pubkey,
|
|
191
|
+
})
|
|
192
|
+
.remainingAccounts(accounts.slice(12))
|
|
193
|
+
.transaction()
|
|
194
|
+
|
|
195
|
+
computeUnitsOverride ||= Math.ceil(
|
|
196
|
+
1.1 *
|
|
197
|
+
((
|
|
198
|
+
await simulateTransaction({
|
|
199
|
+
instructions: execTx.instructions,
|
|
200
|
+
connection: provider.connection,
|
|
201
|
+
payerKey: provider.wallet.publicKey,
|
|
202
|
+
addressLookupTableAccounts,
|
|
203
|
+
computeUnitsOverride,
|
|
204
|
+
})
|
|
205
|
+
).unitsConsumed || 0),
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
// Add compute budget instruction at the beginning of instructions
|
|
209
|
+
execTx.instructions.unshift(
|
|
210
|
+
ComputeBudgetProgram.setComputeUnitLimit({
|
|
211
|
+
units: computeUnitsOverride,
|
|
212
|
+
}),
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
// actual exec tx
|
|
216
|
+
transactions.push([
|
|
217
|
+
'exec',
|
|
218
|
+
toVersionedTransaction(
|
|
219
|
+
execTx.instructions,
|
|
220
|
+
provider.wallet.publicKey,
|
|
221
|
+
recentBlockhash,
|
|
222
|
+
addressLookupTableAccounts,
|
|
223
|
+
),
|
|
224
|
+
])
|
|
225
|
+
|
|
226
|
+
if (alt) {
|
|
227
|
+
transactions.unshift(...alt.initialTxs)
|
|
228
|
+
transactions.push(...alt.finalTxs)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return transactions
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function buildLookupTableTxs(
|
|
235
|
+
provider: AnchorProvider,
|
|
236
|
+
accounts: readonly AccountMeta[],
|
|
237
|
+
): Promise<ExecAlt> {
|
|
238
|
+
const recentSlot = await provider.connection.getSlot('finalized')
|
|
239
|
+
|
|
240
|
+
const [createIx, altAddr] = AddressLookupTableProgram.createLookupTable({
|
|
241
|
+
authority: provider.wallet.publicKey,
|
|
242
|
+
payer: provider.wallet.publicKey,
|
|
243
|
+
recentSlot,
|
|
244
|
+
})
|
|
245
|
+
console.log('Using Address Lookup Table', altAddr.toBase58())
|
|
246
|
+
|
|
247
|
+
const addresses = accounts.map((a) => a.pubkey)
|
|
248
|
+
|
|
249
|
+
if (addresses.length > 256) {
|
|
250
|
+
throw new Error(
|
|
251
|
+
`The number of addresses (${addresses.length}) exceeds the maximum limit imposed by Solana of 256 for Address Lookup Tables`,
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// 1232 bytes is the max size of a transaction, 32 bytes used for each address.
|
|
256
|
+
// 1232 / 32 ~= 38.5
|
|
257
|
+
const firstChunkLength = 28
|
|
258
|
+
const maxAddressesPerTx = 35
|
|
259
|
+
const extendIxs: TransactionInstruction[] = []
|
|
260
|
+
const ranges: [number, number][] = []
|
|
261
|
+
for (
|
|
262
|
+
let [start, end] = [0, firstChunkLength];
|
|
263
|
+
start < addresses.length;
|
|
264
|
+
[start, end] = [end, end + maxAddressesPerTx]
|
|
265
|
+
) {
|
|
266
|
+
const addressesChunk = addresses.slice(start, end)
|
|
267
|
+
const extendIx = AddressLookupTableProgram.extendLookupTable({
|
|
268
|
+
payer: provider.wallet.publicKey,
|
|
269
|
+
authority: provider.wallet.publicKey,
|
|
270
|
+
lookupTable: altAddr,
|
|
271
|
+
addresses: addressesChunk,
|
|
272
|
+
})
|
|
273
|
+
extendIxs.push(extendIx)
|
|
274
|
+
ranges.push([start, start + addressesChunk.length - 1])
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const deactivateIx = AddressLookupTableProgram.deactivateLookupTable({
|
|
278
|
+
lookupTable: altAddr,
|
|
279
|
+
authority: provider.wallet.publicKey,
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
// disable closeTx, to be cleaned in SolanaChain.cleanUpBuffers
|
|
283
|
+
// const closeIx = AddressLookupTableProgram.closeLookupTable({
|
|
284
|
+
// authority: provider.wallet.publicKey,
|
|
285
|
+
// recipient: provider.wallet.publicKey,
|
|
286
|
+
// lookupTable: altAddr,
|
|
287
|
+
// })
|
|
288
|
+
|
|
289
|
+
const { blockhash: recentBlockhash } = await provider.connection.getLatestBlockhash()
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
addressLookupTableAccount: new AddressLookupTableAccount({
|
|
293
|
+
key: altAddr,
|
|
294
|
+
state: {
|
|
295
|
+
deactivationSlot: BigInt(0),
|
|
296
|
+
lastExtendedSlot: recentSlot,
|
|
297
|
+
lastExtendedSlotStartIndex: 0,
|
|
298
|
+
addresses,
|
|
299
|
+
},
|
|
300
|
+
}),
|
|
301
|
+
initialTxs: [
|
|
302
|
+
// first extendIx fits in create tx
|
|
303
|
+
[
|
|
304
|
+
`lookup[create + 0..${ranges[0][1]}]`,
|
|
305
|
+
toVersionedTransaction(
|
|
306
|
+
[createIx, extendIxs[0]],
|
|
307
|
+
provider.wallet.publicKey,
|
|
308
|
+
recentBlockhash,
|
|
309
|
+
),
|
|
310
|
+
],
|
|
311
|
+
...extendIxs
|
|
312
|
+
.slice(1)
|
|
313
|
+
.map<ExecStepTx>((ix, i) => [
|
|
314
|
+
`lookup[${ranges[i + 1][0]}..${ranges[i + 1][1]}]`,
|
|
315
|
+
toVersionedTransaction([ix], provider.wallet.publicKey, recentBlockhash),
|
|
316
|
+
]),
|
|
317
|
+
],
|
|
318
|
+
finalTxs: [
|
|
319
|
+
[
|
|
320
|
+
`lookup[deactivate]`,
|
|
321
|
+
toVersionedTransaction([deactivateIx], provider.wallet.publicKey, recentBlockhash),
|
|
322
|
+
],
|
|
323
|
+
],
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async function bufferedTransactionData(
|
|
328
|
+
offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>,
|
|
329
|
+
serializedReport: Buffer,
|
|
330
|
+
recentBlockhash: string,
|
|
331
|
+
bufferId: Buffer,
|
|
332
|
+
opts?: { clearLeftoverAccounts?: boolean },
|
|
333
|
+
): Promise<ExecStepTx[]> {
|
|
334
|
+
const provider = offrampProgram.provider as AnchorProvider
|
|
335
|
+
|
|
336
|
+
const [bufferAddress] = PublicKey.findProgramAddressSync(
|
|
337
|
+
[Buffer.from('execution_report_buffer'), bufferId, provider.wallet.publicKey.toBuffer()],
|
|
338
|
+
offrampProgram.programId,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
const [configPDA] = PublicKey.findProgramAddressSync(
|
|
342
|
+
[Buffer.from('config')],
|
|
343
|
+
offrampProgram.programId,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
console.log(
|
|
347
|
+
`The bufferID is ${hexlify(bufferId)}, and the PDA address for the buffer is ${bufferAddress.toString()}\nIf this buffering process is aborted, remember to cleanUp the account to recover locked rent.`,
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
const chunkSize = 800
|
|
351
|
+
const bufferedExecTxs: ExecStepTx[] = []
|
|
352
|
+
|
|
353
|
+
const bufferingAccounts = {
|
|
354
|
+
executionReportBuffer: bufferAddress,
|
|
355
|
+
config: configPDA,
|
|
356
|
+
authority: provider.wallet.publicKey,
|
|
357
|
+
systemProgram: SystemProgram.programId,
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (opts?.clearLeftoverAccounts) {
|
|
361
|
+
const clearTx = await offrampProgram.methods
|
|
362
|
+
.closeExecutionReportBuffer(bufferId)
|
|
363
|
+
.accounts(bufferingAccounts)
|
|
364
|
+
.transaction()
|
|
365
|
+
|
|
366
|
+
bufferedExecTxs.push([
|
|
367
|
+
'buffering[clear]',
|
|
368
|
+
toVersionedTransaction(clearTx, provider.wallet.publicKey, recentBlockhash),
|
|
369
|
+
])
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const numChunks = Math.ceil(serializedReport.length / chunkSize)
|
|
373
|
+
for (let i = 0; i < serializedReport.length; i += chunkSize) {
|
|
374
|
+
const end = Math.min(i + chunkSize, serializedReport.length)
|
|
375
|
+
const chunk: Buffer = serializedReport.subarray(i, end)
|
|
376
|
+
|
|
377
|
+
const appendTx = await offrampProgram.methods
|
|
378
|
+
.bufferExecutionReport(bufferId, serializedReport.length, chunk, i / chunkSize, numChunks)
|
|
379
|
+
.accounts(bufferingAccounts)
|
|
380
|
+
.transaction()
|
|
381
|
+
bufferedExecTxs.push([
|
|
382
|
+
`buffering[${i / chunkSize}=${end - i}B]`,
|
|
383
|
+
toVersionedTransaction(appendTx, provider.wallet.publicKey, recentBlockhash),
|
|
384
|
+
])
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return bufferedExecTxs
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function toVersionedTransaction(
|
|
391
|
+
input: Transaction | TransactionInstruction[],
|
|
392
|
+
payerKey: PublicKey,
|
|
393
|
+
recentBlockhash: string,
|
|
394
|
+
addressLookupTableAccounts?: AddressLookupTableAccount[],
|
|
395
|
+
): VersionedTransaction {
|
|
396
|
+
const instructions: TransactionInstruction[] = Array.isArray(input) ? input : input.instructions
|
|
397
|
+
|
|
398
|
+
const message = new TransactionMessage({ payerKey, recentBlockhash, instructions })
|
|
399
|
+
return new VersionedTransaction(message.compileToV0Message(addressLookupTableAccounts))
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
async function getManuallyExecuteInputs({
|
|
403
|
+
execReport,
|
|
404
|
+
offrampProgram,
|
|
405
|
+
transmitter,
|
|
406
|
+
bufferId,
|
|
407
|
+
}: {
|
|
408
|
+
execReport: ExecutionReport<CCIPMessage_V1_6_Solana>
|
|
409
|
+
offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>
|
|
410
|
+
transmitter: string
|
|
411
|
+
bufferId?: Buffer
|
|
412
|
+
}) {
|
|
413
|
+
const executionReport = prepareExecutionReport(execReport)
|
|
414
|
+
|
|
415
|
+
const messageAccountMetas = execReport.message.accounts.map((acc, index) => {
|
|
416
|
+
const bitmap = BigInt(execReport.message.accountIsWritableBitmap)
|
|
417
|
+
const isWritable = (bitmap & (1n << BigInt(index))) !== 0n
|
|
418
|
+
|
|
419
|
+
return {
|
|
420
|
+
pubkey: new PublicKey(acc),
|
|
421
|
+
isSigner: false,
|
|
422
|
+
isWritable,
|
|
423
|
+
}
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
// Convert message.receiver to AccountMeta and prepend to messaging accounts
|
|
427
|
+
const receiverAccountMeta = {
|
|
428
|
+
pubkey: new PublicKey(execReport.message.receiver),
|
|
429
|
+
isSigner: false,
|
|
430
|
+
isWritable: false,
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
console.debug('Message receiver:', execReport.message.receiver)
|
|
434
|
+
|
|
435
|
+
// Prepend receiver to messaging accounts
|
|
436
|
+
const messagingAccounts: AccountMeta[] =
|
|
437
|
+
execReport.message.receiver !== PublicKey.default.toBase58()
|
|
438
|
+
? [receiverAccountMeta, ...messageAccountMetas]
|
|
439
|
+
: [] // on plain token transfers, there are no messaging accounts
|
|
440
|
+
const tokenTransferAndOffchainData: IdlTypes<
|
|
441
|
+
typeof CCIP_OFFRAMP_IDL
|
|
442
|
+
>['TokenTransferAndOffchainData'][] = execReport.message.tokenAmounts.map((ta, idx) => ({
|
|
443
|
+
data: bytesToBuffer(encodeSolanaOffchainTokenData(execReport.offchainTokenData[idx])),
|
|
444
|
+
transfer: {
|
|
445
|
+
sourcePoolAddress: bytesToBuffer(ta.sourcePoolAddress),
|
|
446
|
+
destTokenAddress: new PublicKey(ta.destTokenAddress),
|
|
447
|
+
destGasAmount: Number(ta.destGasAmount),
|
|
448
|
+
extraData: bytesToBuffer(ta.extraData || '0x'),
|
|
449
|
+
amount: {
|
|
450
|
+
leBytes: Array.from(toLeArray(ta.amount, 32)),
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
}))
|
|
454
|
+
|
|
455
|
+
const {
|
|
456
|
+
accounts,
|
|
457
|
+
addressLookupTableAccounts: addressLookupTables,
|
|
458
|
+
tokenIndexes,
|
|
459
|
+
} = await autoDeriveExecutionAccounts({
|
|
460
|
+
offrampProgram,
|
|
461
|
+
originalSender: bytesToBuffer(execReport.message.sender),
|
|
462
|
+
transmitter: new PublicKey(transmitter),
|
|
463
|
+
messagingAccounts,
|
|
464
|
+
sourceChainSelector: execReport.message.header.sourceChainSelector,
|
|
465
|
+
tokenTransferAndOffchainData,
|
|
466
|
+
merkleRoot: bytesToBuffer(execReport.merkleRoot),
|
|
467
|
+
bufferId,
|
|
468
|
+
tokenReceiver: new PublicKey(execReport.message.tokenReceiver),
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
return {
|
|
472
|
+
executionReport,
|
|
473
|
+
tokenIndexes,
|
|
474
|
+
accounts,
|
|
475
|
+
addressLookupTables,
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function prepareExecutionReport({
|
|
480
|
+
message,
|
|
481
|
+
offchainTokenData,
|
|
482
|
+
proofs,
|
|
483
|
+
}: ExecutionReport<CCIPMessage_V1_6_Solana>): IdlTypes<
|
|
484
|
+
typeof CCIP_OFFRAMP_IDL
|
|
485
|
+
>['ExecutionReportSingleChain'] {
|
|
486
|
+
return {
|
|
487
|
+
sourceChainSelector: new BN(message.header.sourceChainSelector.toString()),
|
|
488
|
+
message: {
|
|
489
|
+
header: {
|
|
490
|
+
messageId: Array.from(getDataBytes(message.header.messageId)),
|
|
491
|
+
sourceChainSelector: new BN(message.header.sourceChainSelector),
|
|
492
|
+
destChainSelector: new BN(message.header.destChainSelector),
|
|
493
|
+
sequenceNumber: new BN(message.header.sequenceNumber),
|
|
494
|
+
nonce: new BN(message.header.nonce),
|
|
495
|
+
},
|
|
496
|
+
sender: bytesToBuffer(message.sender),
|
|
497
|
+
data: bytesToBuffer(message.data),
|
|
498
|
+
tokenReceiver: new PublicKey(message.tokenReceiver),
|
|
499
|
+
tokenAmounts: message.tokenAmounts.map((token) => ({
|
|
500
|
+
sourcePoolAddress: bytesToBuffer(token.sourcePoolAddress),
|
|
501
|
+
destTokenAddress: new PublicKey(token.destTokenAddress),
|
|
502
|
+
destGasAmount: Number(token.destGasAmount),
|
|
503
|
+
extraData: bytesToBuffer(token.extraData),
|
|
504
|
+
amount: {
|
|
505
|
+
leBytes: Array.from(toLeArray(token.amount, 32)),
|
|
506
|
+
},
|
|
507
|
+
})),
|
|
508
|
+
extraArgs: {
|
|
509
|
+
computeUnits: Number(message.computeUnits),
|
|
510
|
+
isWritableBitmap: new BN(message.accountIsWritableBitmap),
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
offchainTokenData: offchainTokenData.map((d) =>
|
|
514
|
+
bytesToBuffer(encodeSolanaOffchainTokenData(d)),
|
|
515
|
+
),
|
|
516
|
+
proofs: proofs.map((p) => Array.from(getDataBytes(p))),
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
async function autoDeriveExecutionAccounts({
|
|
521
|
+
offrampProgram,
|
|
522
|
+
originalSender,
|
|
523
|
+
transmitter,
|
|
524
|
+
messagingAccounts,
|
|
525
|
+
sourceChainSelector,
|
|
526
|
+
tokenTransferAndOffchainData,
|
|
527
|
+
merkleRoot,
|
|
528
|
+
tokenReceiver,
|
|
529
|
+
bufferId,
|
|
530
|
+
}: {
|
|
531
|
+
offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>
|
|
532
|
+
originalSender: Buffer
|
|
533
|
+
transmitter: PublicKey
|
|
534
|
+
messagingAccounts: IdlTypes<typeof CCIP_OFFRAMP_IDL>['CcipAccountMeta'][]
|
|
535
|
+
sourceChainSelector: bigint
|
|
536
|
+
tokenTransferAndOffchainData: Array<
|
|
537
|
+
IdlTypes<typeof CCIP_OFFRAMP_IDL>['TokenTransferAndOffchainData']
|
|
538
|
+
>
|
|
539
|
+
merkleRoot: Buffer
|
|
540
|
+
tokenReceiver: PublicKey
|
|
541
|
+
bufferId?: Buffer
|
|
542
|
+
}) {
|
|
543
|
+
const derivedAccounts: AccountMeta[] = []
|
|
544
|
+
const lookupTables: PublicKey[] = []
|
|
545
|
+
const tokenIndices: number[] = []
|
|
546
|
+
let askWith: AccountMeta[] = []
|
|
547
|
+
let stage = 'Start'
|
|
548
|
+
let tokenIndex = 0
|
|
549
|
+
|
|
550
|
+
const [configPDA] = PublicKey.findProgramAddressSync(
|
|
551
|
+
[Buffer.from('config')],
|
|
552
|
+
offrampProgram.programId,
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
while (true) {
|
|
556
|
+
const params: IdlTypes<typeof CCIP_OFFRAMP_IDL>['DeriveAccountsExecuteParams'] = {
|
|
557
|
+
executeCaller: transmitter,
|
|
558
|
+
messageAccounts: messagingAccounts,
|
|
559
|
+
sourceChainSelector: new BN(sourceChainSelector.toString()),
|
|
560
|
+
originalSender: originalSender,
|
|
561
|
+
tokenTransfers: tokenTransferAndOffchainData,
|
|
562
|
+
merkleRoot: Array.from(merkleRoot),
|
|
563
|
+
bufferId: bufferId ?? Buffer.from([]),
|
|
564
|
+
tokenReceiver,
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Workarounds for tx-too-large issues during account derivation
|
|
568
|
+
if (/BuildDynamicAccounts/.test(stage)) {
|
|
569
|
+
params.messageAccounts = [] // omit messaging accounts
|
|
570
|
+
} else {
|
|
571
|
+
params.tokenTransfers = tokenTransferAndOffchainData.map((tt) => ({
|
|
572
|
+
...tt,
|
|
573
|
+
data: Buffer.from([]), // omit offchain token data
|
|
574
|
+
}))
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// copy of Program which avoids signing every simulation
|
|
578
|
+
const readOnlyProgram = new Program(
|
|
579
|
+
offrampProgram.idl,
|
|
580
|
+
offrampProgram.programId,
|
|
581
|
+
simulationProvider(offrampProgram.provider.connection, transmitter),
|
|
582
|
+
)
|
|
583
|
+
// Execute as a view call to get the response
|
|
584
|
+
const response = (await readOnlyProgram.methods
|
|
585
|
+
.deriveAccountsExecute(params, stage)
|
|
586
|
+
.accounts({
|
|
587
|
+
config: configPDA,
|
|
588
|
+
})
|
|
589
|
+
.remainingAccounts(askWith)
|
|
590
|
+
.view()
|
|
591
|
+
.catch((error: unknown) => {
|
|
592
|
+
console.error('Error deriving accounts:', error)
|
|
593
|
+
console.error('Params:', params)
|
|
594
|
+
throw error as Error
|
|
595
|
+
})) as IdlTypes<typeof CCIP_OFFRAMP_IDL>['DeriveAccountsResponse']
|
|
596
|
+
|
|
597
|
+
// Check if we're at the start of a token transfer
|
|
598
|
+
const isStartOfToken = /^TokenTransferStaticAccounts\/\d+\/0$/.test(response.currentStage)
|
|
599
|
+
if (isStartOfToken) {
|
|
600
|
+
const numKnownAccounts = 12
|
|
601
|
+
tokenIndices.push(tokenIndex - numKnownAccounts)
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Update token index
|
|
605
|
+
tokenIndex += response.accountsToSave.length
|
|
606
|
+
|
|
607
|
+
console.debug('After stage', stage, 'tokenIndices', tokenIndices, 'nextTokenIndex', tokenIndex)
|
|
608
|
+
|
|
609
|
+
// Collect the derived accounts
|
|
610
|
+
for (const meta of response.accountsToSave) {
|
|
611
|
+
derivedAccounts.push({
|
|
612
|
+
pubkey: meta.pubkey,
|
|
613
|
+
isWritable: meta.isWritable,
|
|
614
|
+
isSigner: meta.isSigner,
|
|
615
|
+
})
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// Prepare askWith for next iteration
|
|
619
|
+
askWith = response.askAgainWith.map((meta) => ({
|
|
620
|
+
pubkey: meta.pubkey,
|
|
621
|
+
isWritable: meta.isWritable,
|
|
622
|
+
isSigner: meta.isSigner,
|
|
623
|
+
}))
|
|
624
|
+
|
|
625
|
+
// Collect lookup tables
|
|
626
|
+
lookupTables.push(...response.lookUpTablesToSave)
|
|
627
|
+
|
|
628
|
+
// Check if derivation is complete
|
|
629
|
+
if (!response.nextStage || response.nextStage.length === 0) {
|
|
630
|
+
break
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
stage = response.nextStage
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
console.debug('Resulting derived accounts:', derivedAccounts)
|
|
637
|
+
console.debug('Resulting derived address lookup tables:', lookupTables)
|
|
638
|
+
console.debug('Resulting derived token indexes:', tokenIndices)
|
|
639
|
+
|
|
640
|
+
return {
|
|
641
|
+
accounts: derivedAccounts,
|
|
642
|
+
addressLookupTableAccounts: lookupTables,
|
|
643
|
+
tokenIndexes: Buffer.from(tokenIndices),
|
|
644
|
+
}
|
|
645
|
+
}
|