@chainlink/ccip-sdk 0.91.0 → 0.92.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/README.md +127 -80
- package/dist/aptos/hasher.d.ts.map +1 -1
- package/dist/aptos/hasher.js +7 -6
- package/dist/aptos/hasher.js.map +1 -1
- package/dist/aptos/index.d.ts +7 -2
- package/dist/aptos/index.d.ts.map +1 -1
- package/dist/aptos/index.js +29 -20
- package/dist/aptos/index.js.map +1 -1
- package/dist/aptos/logs.d.ts +5 -3
- package/dist/aptos/logs.d.ts.map +1 -1
- package/dist/aptos/logs.js +64 -27
- package/dist/aptos/logs.js.map +1 -1
- package/dist/aptos/token.d.ts.map +1 -1
- package/dist/aptos/token.js +2 -1
- package/dist/aptos/token.js.map +1 -1
- package/dist/aptos/types.js +6 -6
- package/dist/aptos/types.js.map +1 -1
- package/dist/chain.d.ts +36 -11
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +34 -2
- package/dist/chain.js.map +1 -1
- package/dist/commits.d.ts +2 -3
- package/dist/commits.d.ts.map +1 -1
- package/dist/commits.js +19 -8
- package/dist/commits.js.map +1 -1
- package/dist/errors/CCIPError.d.ts +48 -0
- package/dist/errors/CCIPError.d.ts.map +1 -0
- package/dist/errors/CCIPError.js +65 -0
- package/dist/errors/CCIPError.js.map +1 -0
- package/dist/errors/codes.d.ts +120 -0
- package/dist/errors/codes.d.ts.map +1 -0
- package/dist/errors/codes.js +156 -0
- package/dist/errors/codes.js.map +1 -0
- package/dist/errors/index.d.ts +26 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +51 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/recovery.d.ts +6 -0
- package/dist/errors/recovery.d.ts.map +1 -0
- package/dist/errors/recovery.js +118 -0
- package/dist/errors/recovery.js.map +1 -0
- package/dist/errors/specialized.d.ts +637 -0
- package/dist/errors/specialized.d.ts.map +1 -0
- package/dist/errors/specialized.js +1298 -0
- package/dist/errors/specialized.js.map +1 -0
- package/dist/errors/utils.d.ts +11 -0
- package/dist/errors/utils.d.ts.map +1 -0
- package/dist/errors/utils.js +61 -0
- package/dist/errors/utils.js.map +1 -0
- package/dist/evm/abi/CommitStore_1_5.js +1 -1
- package/dist/evm/abi/LockReleaseTokenPool_1_5.js +1 -1
- package/dist/evm/abi/OffRamp_1_5.js +1 -1
- package/dist/evm/abi/OnRamp_1_5.js +1 -1
- package/dist/evm/abi/PriceRegistry_1_2.d.ts +443 -0
- package/dist/evm/abi/PriceRegistry_1_2.d.ts.map +1 -0
- package/dist/evm/abi/PriceRegistry_1_2.js +439 -0
- package/dist/evm/abi/PriceRegistry_1_2.js.map +1 -0
- package/dist/evm/const.d.ts +1 -0
- package/dist/evm/const.d.ts.map +1 -1
- package/dist/evm/const.js +2 -0
- package/dist/evm/const.js.map +1 -1
- package/dist/evm/hasher.d.ts.map +1 -1
- package/dist/evm/hasher.js +7 -6
- package/dist/evm/hasher.js.map +1 -1
- package/dist/evm/index.d.ts +9 -13
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +85 -68
- package/dist/evm/index.js.map +1 -1
- package/dist/evm/logs.d.ts.map +1 -1
- package/dist/evm/logs.js +47 -16
- package/dist/evm/logs.js.map +1 -1
- package/dist/evm/messages.d.ts +7 -6
- package/dist/evm/messages.d.ts.map +1 -1
- package/dist/evm/offchain.js +1 -1
- package/dist/evm/offchain.js.map +1 -1
- package/dist/evm/types.d.ts +10 -0
- package/dist/evm/types.d.ts.map +1 -0
- package/dist/evm/types.js +2 -0
- package/dist/evm/types.js.map +1 -0
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +9 -5
- package/dist/execution.js.map +1 -1
- package/dist/extra-args.d.ts.map +1 -1
- package/dist/extra-args.js +4 -3
- package/dist/extra-args.js.map +1 -1
- package/dist/gas.d.ts.map +1 -1
- package/dist/gas.js +3 -2
- package/dist/gas.js.map +1 -1
- package/dist/hasher/hasher.d.ts.map +1 -1
- package/dist/hasher/hasher.js +2 -1
- package/dist/hasher/hasher.js.map +1 -1
- package/dist/hasher/merklemulti.d.ts.map +1 -1
- package/dist/hasher/merklemulti.js +9 -8
- package/dist/hasher/merklemulti.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/offchain.d.ts.map +1 -1
- package/dist/offchain.js +5 -8
- package/dist/offchain.js.map +1 -1
- package/dist/requests.d.ts +1 -1
- package/dist/requests.d.ts.map +1 -1
- package/dist/requests.js +37 -43
- package/dist/requests.js.map +1 -1
- package/dist/selectors.d.ts.map +1 -1
- package/dist/selectors.js +22 -0
- package/dist/selectors.js.map +1 -1
- package/dist/solana/cleanup.d.ts +2 -2
- package/dist/solana/cleanup.d.ts.map +1 -1
- package/dist/solana/cleanup.js +2 -3
- package/dist/solana/cleanup.js.map +1 -1
- package/dist/solana/exec.d.ts.map +1 -1
- package/dist/solana/exec.js +12 -12
- package/dist/solana/exec.js.map +1 -1
- package/dist/solana/hasher.d.ts.map +1 -1
- package/dist/solana/hasher.js +6 -5
- package/dist/solana/hasher.js.map +1 -1
- package/dist/solana/index.d.ts +30 -13
- package/dist/solana/index.d.ts.map +1 -1
- package/dist/solana/index.js +96 -143
- package/dist/solana/index.js.map +1 -1
- package/dist/solana/logs.d.ts +15 -0
- package/dist/solana/logs.d.ts.map +1 -0
- package/dist/solana/logs.js +106 -0
- package/dist/solana/logs.js.map +1 -0
- package/dist/solana/offchain.d.ts.map +1 -1
- package/dist/solana/offchain.js +6 -5
- package/dist/solana/offchain.js.map +1 -1
- package/dist/solana/patchBorsh.d.ts.map +1 -1
- package/dist/solana/patchBorsh.js +3 -2
- package/dist/solana/patchBorsh.js.map +1 -1
- package/dist/solana/send.d.ts.map +1 -1
- package/dist/solana/send.js +8 -7
- package/dist/solana/send.js.map +1 -1
- package/dist/solana/utils.d.ts +7 -8
- package/dist/solana/utils.d.ts.map +1 -1
- package/dist/solana/utils.js +23 -11
- package/dist/solana/utils.js.map +1 -1
- package/dist/sui/discovery.d.ts +18 -0
- package/dist/sui/discovery.d.ts.map +1 -0
- package/dist/sui/discovery.js +116 -0
- package/dist/sui/discovery.js.map +1 -0
- package/dist/sui/events.d.ts +36 -0
- package/dist/sui/events.d.ts.map +1 -0
- package/dist/sui/events.js +179 -0
- package/dist/sui/events.js.map +1 -0
- package/dist/sui/hasher.d.ts.map +1 -1
- package/dist/sui/hasher.js +6 -5
- package/dist/sui/hasher.js.map +1 -1
- package/dist/sui/index.d.ts +69 -41
- package/dist/sui/index.d.ts.map +1 -1
- package/dist/sui/index.js +402 -65
- package/dist/sui/index.js.map +1 -1
- package/dist/sui/manuallyExec/encoder.d.ts +8 -0
- package/dist/sui/manuallyExec/encoder.d.ts.map +1 -0
- package/dist/sui/manuallyExec/encoder.js +76 -0
- package/dist/sui/manuallyExec/encoder.js.map +1 -0
- package/dist/sui/manuallyExec/index.d.ts +37 -0
- package/dist/sui/manuallyExec/index.d.ts.map +1 -0
- package/dist/sui/manuallyExec/index.js +81 -0
- package/dist/sui/manuallyExec/index.js.map +1 -0
- package/dist/sui/objects.d.ts +46 -0
- package/dist/sui/objects.d.ts.map +1 -0
- package/dist/sui/objects.js +259 -0
- package/dist/sui/objects.js.map +1 -0
- package/dist/ton/bindings/offramp.d.ts +48 -0
- package/dist/ton/bindings/offramp.d.ts.map +1 -0
- package/dist/ton/bindings/offramp.js +63 -0
- package/dist/ton/bindings/offramp.js.map +1 -0
- package/dist/ton/bindings/onramp.d.ts +40 -0
- package/dist/ton/bindings/onramp.d.ts.map +1 -0
- package/dist/ton/bindings/onramp.js +51 -0
- package/dist/ton/bindings/onramp.js.map +1 -0
- package/dist/ton/bindings/router.d.ts +47 -0
- package/dist/ton/bindings/router.d.ts.map +1 -0
- package/dist/ton/bindings/router.js +51 -0
- package/dist/ton/bindings/router.js.map +1 -0
- package/dist/ton/exec.d.ts +18 -0
- package/dist/ton/exec.d.ts.map +1 -0
- package/dist/ton/exec.js +28 -0
- package/dist/ton/exec.js.map +1 -0
- package/dist/ton/hasher.d.ts +27 -0
- package/dist/ton/hasher.d.ts.map +1 -0
- package/dist/ton/hasher.js +134 -0
- package/dist/ton/hasher.js.map +1 -0
- package/dist/ton/index.d.ts +247 -0
- package/dist/ton/index.d.ts.map +1 -0
- package/dist/ton/index.js +781 -0
- package/dist/ton/index.js.map +1 -0
- package/dist/ton/logs.d.ts +26 -0
- package/dist/ton/logs.d.ts.map +1 -0
- package/dist/ton/logs.js +126 -0
- package/dist/ton/logs.js.map +1 -0
- package/dist/ton/types.d.ts +37 -0
- package/dist/ton/types.d.ts.map +1 -0
- package/dist/ton/types.js +92 -0
- package/dist/ton/types.js.map +1 -0
- package/dist/ton/utils.d.ts +67 -0
- package/dist/ton/utils.d.ts.map +1 -0
- package/dist/ton/utils.js +425 -0
- package/dist/ton/utils.js.map +1 -0
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +10 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +52 -17
- package/dist/utils.js.map +1 -1
- package/package.json +12 -10
- package/src/aptos/hasher.ts +10 -6
- package/src/aptos/index.ts +50 -31
- package/src/aptos/logs.ts +85 -29
- package/src/aptos/token.ts +5 -1
- package/src/aptos/types.ts +6 -6
- package/src/chain.ts +83 -12
- package/src/commits.ts +23 -11
- package/src/errors/CCIPError.ts +86 -0
- package/src/errors/codes.ts +179 -0
- package/src/errors/index.ts +175 -0
- package/src/errors/recovery.ts +170 -0
- package/src/errors/specialized.ts +1655 -0
- package/src/errors/utils.ts +73 -0
- package/src/evm/abi/CommitStore_1_5.ts +1 -1
- package/src/evm/abi/LockReleaseTokenPool_1_5.ts +1 -1
- package/src/evm/abi/OffRamp_1_5.ts +1 -1
- package/src/evm/abi/OnRamp_1_5.ts +1 -1
- package/src/evm/abi/PriceRegistry_1_2.ts +438 -0
- package/src/evm/const.ts +2 -0
- package/src/evm/hasher.ts +7 -6
- package/src/evm/index.ts +104 -86
- package/src/evm/logs.ts +64 -16
- package/src/evm/messages.ts +14 -14
- package/src/evm/offchain.ts +1 -1
- package/src/evm/types.ts +11 -0
- package/src/execution.ts +13 -9
- package/src/extra-args.ts +4 -3
- package/src/gas.ts +10 -3
- package/src/hasher/hasher.ts +2 -1
- package/src/hasher/merklemulti.ts +18 -8
- package/src/index.ts +14 -2
- package/src/offchain.ts +10 -14
- package/src/requests.ts +51 -53
- package/src/selectors.ts +23 -0
- package/src/solana/cleanup.ts +2 -4
- package/src/solana/exec.ts +13 -13
- package/src/solana/hasher.ts +9 -5
- package/src/solana/index.ts +126 -200
- package/src/solana/logs.ts +155 -0
- package/src/solana/offchain.ts +10 -7
- package/src/solana/patchBorsh.ts +3 -2
- package/src/solana/send.ts +14 -7
- package/src/solana/utils.ts +31 -17
- package/src/sui/discovery.ts +163 -0
- package/src/sui/events.ts +328 -0
- package/src/sui/hasher.ts +6 -5
- package/src/sui/index.ts +528 -80
- package/src/sui/manuallyExec/encoder.ts +88 -0
- package/src/sui/manuallyExec/index.ts +137 -0
- package/src/sui/objects.ts +358 -0
- package/src/ton/bindings/offramp.ts +96 -0
- package/src/ton/bindings/onramp.ts +72 -0
- package/src/ton/bindings/router.ts +65 -0
- package/src/ton/exec.ts +44 -0
- package/src/ton/hasher.ts +184 -0
- package/src/ton/index.ts +989 -0
- package/src/ton/logs.ts +157 -0
- package/src/ton/types.ts +143 -0
- package/src/ton/utils.ts +514 -0
- package/src/types.ts +6 -2
- package/src/utils.ts +58 -23
- package/tsconfig.json +2 -1
package/src/aptos/logs.ts
CHANGED
|
@@ -8,7 +8,17 @@ import {
|
|
|
8
8
|
import { memoize } from 'micro-memoize'
|
|
9
9
|
|
|
10
10
|
import type { LogFilter } from '../chain.ts'
|
|
11
|
+
import {
|
|
12
|
+
CCIPAptosAddressModuleRequiredError,
|
|
13
|
+
CCIPAptosTopicInvalidError,
|
|
14
|
+
CCIPAptosTransactionTypeUnexpectedError,
|
|
15
|
+
CCIPLogsWatchRequiresFinalityError,
|
|
16
|
+
CCIPLogsWatchRequiresStartError,
|
|
17
|
+
} from '../errors/index.ts'
|
|
11
18
|
import type { Log_ } from '../types.ts'
|
|
19
|
+
import { sleep } from '../utils.ts'
|
|
20
|
+
|
|
21
|
+
const DEFAULT_POLL_INTERVAL = 5e3
|
|
12
22
|
|
|
13
23
|
const eventToHandler = {
|
|
14
24
|
CCIPMessageSent: 'OnRampState/ccip_message_sent_events',
|
|
@@ -30,29 +40,24 @@ export async function getUserTxByVersion(
|
|
|
30
40
|
ledgerVersion: version,
|
|
31
41
|
})
|
|
32
42
|
if (tx.type !== TransactionResponseType.User)
|
|
33
|
-
throw new
|
|
43
|
+
throw new CCIPAptosTransactionTypeUnexpectedError(tx.type)
|
|
34
44
|
return tx
|
|
35
45
|
}
|
|
36
46
|
|
|
37
47
|
/**
|
|
38
48
|
* Gets the timestamp for a given transaction version.
|
|
39
49
|
* @param provider - Aptos provider instance.
|
|
40
|
-
* @param version -
|
|
41
|
-
* @returns
|
|
50
|
+
* @param version - Positive version number, negative block depth finality, or 'finalized'.
|
|
51
|
+
* @returns Epoch timestamp in seconds.
|
|
42
52
|
*/
|
|
43
53
|
export async function getVersionTimestamp(
|
|
44
54
|
provider: Aptos,
|
|
45
55
|
version: number | 'finalized',
|
|
46
56
|
): Promise<number> {
|
|
47
|
-
if (version
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
})
|
|
52
|
-
return +(tx as UserTransactionResponse).timestamp / 1e6
|
|
53
|
-
}
|
|
54
|
-
const tx = await getUserTxByVersion(provider, version)
|
|
55
|
-
return +tx.timestamp / 1e6
|
|
57
|
+
if (typeof version !== 'number') version = 0
|
|
58
|
+
if (version <= 0) version = +(await provider.getLedgerInfo()).ledger_version + version
|
|
59
|
+
const tx = await provider.getTransactionByVersion({ ledgerVersion: version })
|
|
60
|
+
return +(tx as UserTransactionResponse).timestamp / 1e6
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
type ResEvent = AptosEvent & { version: string }
|
|
@@ -84,12 +89,16 @@ async function binarySearchFirst(
|
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
async function* fetchEventsForward(
|
|
87
|
-
provider: Aptos,
|
|
88
|
-
opts: LogFilter,
|
|
92
|
+
{ provider }: { provider: Aptos },
|
|
93
|
+
opts: LogFilter & { pollInterval?: number },
|
|
89
94
|
eventHandlerField: string,
|
|
90
95
|
stateAddr: string,
|
|
91
96
|
limit = 100,
|
|
92
97
|
): AsyncGenerator<ResEvent> {
|
|
98
|
+
if (opts.watch && typeof opts.endBlock === 'number' && opts.endBlock > 0)
|
|
99
|
+
throw new CCIPLogsWatchRequiresFinalityError(opts.endBlock)
|
|
100
|
+
opts.endBlock ||= 'latest'
|
|
101
|
+
|
|
93
102
|
const fetchBatch = memoize(
|
|
94
103
|
async (start?: number) => {
|
|
95
104
|
const { data }: { data: ResEvent[] } = await getAptosFullNode({
|
|
@@ -101,7 +110,7 @@ async function* fetchEventsForward(
|
|
|
101
110
|
if (!start) fetchBatch.cache.set([+data[0].sequence_number], Promise.resolve(data))
|
|
102
111
|
return data
|
|
103
112
|
},
|
|
104
|
-
{ maxArgs: 1, maxSize: 100 },
|
|
113
|
+
{ maxArgs: 1, maxSize: 100, async: true },
|
|
105
114
|
)
|
|
106
115
|
|
|
107
116
|
const initialBatch = await fetchBatch()
|
|
@@ -124,8 +133,25 @@ async function* fetchEventsForward(
|
|
|
124
133
|
start = end - limit + 1
|
|
125
134
|
}
|
|
126
135
|
|
|
127
|
-
let
|
|
128
|
-
|
|
136
|
+
let notAfter =
|
|
137
|
+
typeof opts.endBlock !== 'number'
|
|
138
|
+
? undefined
|
|
139
|
+
: opts.endBlock < 0
|
|
140
|
+
? memoize(
|
|
141
|
+
async () =>
|
|
142
|
+
+(await provider.getLedgerInfo()).ledger_version + (opts.endBlock as number),
|
|
143
|
+
{
|
|
144
|
+
async: true,
|
|
145
|
+
maxArgs: 0,
|
|
146
|
+
expires: opts.pollInterval || DEFAULT_POLL_INTERVAL,
|
|
147
|
+
},
|
|
148
|
+
)
|
|
149
|
+
: opts.endBlock
|
|
150
|
+
|
|
151
|
+
let first = true,
|
|
152
|
+
catchedUp = false
|
|
153
|
+
while (opts.watch || !catchedUp) {
|
|
154
|
+
const lastReq = performance.now()
|
|
129
155
|
const data = await fetchBatch(start)
|
|
130
156
|
if (
|
|
131
157
|
first &&
|
|
@@ -139,17 +165,40 @@ async function* fetchEventsForward(
|
|
|
139
165
|
})
|
|
140
166
|
data.splice(0, actualStart - 1)
|
|
141
167
|
}
|
|
168
|
+
|
|
169
|
+
if (!first && catchedUp && typeof opts.endBlock === 'number' && opts.endBlock < 0)
|
|
170
|
+
notAfter = +(await provider.getLedgerInfo()).ledger_version + opts.endBlock
|
|
171
|
+
|
|
142
172
|
first = false
|
|
173
|
+
|
|
143
174
|
for (const ev of data) {
|
|
144
175
|
if (opts.startBlock && +ev.version < opts.startBlock) continue
|
|
145
|
-
|
|
176
|
+
// there may be an unknown interval between yields, so we support memoized negative finality
|
|
177
|
+
if (
|
|
178
|
+
notAfter &&
|
|
179
|
+
+ev.version > (typeof notAfter === 'function' ? await notAfter() : notAfter)
|
|
180
|
+
) {
|
|
181
|
+
catchedUp = true
|
|
182
|
+
break
|
|
183
|
+
}
|
|
184
|
+
const start_: number = +ev.sequence_number
|
|
185
|
+
start = start_ + 1
|
|
146
186
|
yield ev
|
|
147
187
|
}
|
|
188
|
+
catchedUp ||= start >= end
|
|
189
|
+
if (opts.watch && catchedUp) {
|
|
190
|
+
let break$ = sleep(
|
|
191
|
+
Math.max((opts.pollInterval || DEFAULT_POLL_INTERVAL) - (performance.now() - lastReq), 1),
|
|
192
|
+
).then(() => false)
|
|
193
|
+
if (opts.watch instanceof Promise)
|
|
194
|
+
break$ = Promise.race([break$, opts.watch.then(() => true)])
|
|
195
|
+
if (await break$) break
|
|
196
|
+
}
|
|
148
197
|
}
|
|
149
198
|
}
|
|
150
199
|
|
|
151
200
|
async function* fetchEventsBackward(
|
|
152
|
-
provider: Aptos,
|
|
201
|
+
{ provider }: { provider: Aptos },
|
|
153
202
|
opts: LogFilter,
|
|
154
203
|
eventHandlerField: string,
|
|
155
204
|
stateAddr: string,
|
|
@@ -157,6 +206,12 @@ async function* fetchEventsBackward(
|
|
|
157
206
|
): AsyncGenerator<ResEvent> {
|
|
158
207
|
let start
|
|
159
208
|
let cont = true
|
|
209
|
+
const notAfter =
|
|
210
|
+
typeof opts.endBlock !== 'number'
|
|
211
|
+
? undefined
|
|
212
|
+
: opts.endBlock < 0
|
|
213
|
+
? +(await provider.getLedgerInfo()).ledger_version + opts.endBlock
|
|
214
|
+
: opts.endBlock
|
|
160
215
|
do {
|
|
161
216
|
const { data } = await getAptosFullNode<object, ResEvent[]>({
|
|
162
217
|
aptosConfig: provider.config,
|
|
@@ -170,7 +225,7 @@ async function* fetchEventsBackward(
|
|
|
170
225
|
else start = Math.max(+data[0].sequence_number - limit, 1)
|
|
171
226
|
|
|
172
227
|
for (const ev of data.reverse()) {
|
|
173
|
-
if (
|
|
228
|
+
if (notAfter && +ev.version > notAfter) continue
|
|
174
229
|
if (+ev.sequence_number <= 1) cont = false
|
|
175
230
|
yield ev
|
|
176
231
|
}
|
|
@@ -184,20 +239,19 @@ async function* fetchEventsBackward(
|
|
|
184
239
|
* @returns Async generator of log entries.
|
|
185
240
|
*/
|
|
186
241
|
export async function* streamAptosLogs(
|
|
187
|
-
provider: Aptos,
|
|
242
|
+
ctx: { provider: Aptos },
|
|
188
243
|
opts: LogFilter & { versionAsHash?: boolean },
|
|
189
244
|
): AsyncGenerator<Log_> {
|
|
190
245
|
const limit = 100
|
|
191
|
-
if (!opts.address || !opts.address.includes('::'))
|
|
192
|
-
throw new Error('address with module is required')
|
|
246
|
+
if (!opts.address || !opts.address.includes('::')) throw new CCIPAptosAddressModuleRequiredError()
|
|
193
247
|
if (opts.topics?.length !== 1 || typeof opts.topics[0] !== 'string')
|
|
194
|
-
throw new
|
|
248
|
+
throw new CCIPAptosTopicInvalidError()
|
|
195
249
|
let eventHandlerField = opts.topics[0]
|
|
196
250
|
if (!eventHandlerField.includes('/')) {
|
|
197
251
|
eventHandlerField = (eventToHandler as Record<string, string>)[eventHandlerField]
|
|
198
|
-
if (!eventHandlerField) throw new
|
|
252
|
+
if (!eventHandlerField) throw new CCIPAptosTopicInvalidError(opts.topics[0])
|
|
199
253
|
}
|
|
200
|
-
const [stateAddr] = await provider.view<[string]>({
|
|
254
|
+
const [stateAddr] = await ctx.provider.view<[string]>({
|
|
201
255
|
payload: {
|
|
202
256
|
function: `${opts.address}::get_state_address` as `0x${string}::${string}::get_state_address`,
|
|
203
257
|
},
|
|
@@ -205,10 +259,12 @@ export async function* streamAptosLogs(
|
|
|
205
259
|
|
|
206
260
|
let eventsIter
|
|
207
261
|
if (opts.startBlock || opts.startTime) {
|
|
208
|
-
eventsIter = fetchEventsForward(
|
|
262
|
+
eventsIter = fetchEventsForward(ctx, opts, eventHandlerField, stateAddr, limit)
|
|
263
|
+
} else if (opts.watch) {
|
|
264
|
+
throw new CCIPLogsWatchRequiresStartError()
|
|
209
265
|
} else {
|
|
210
266
|
// backwards, just paginate down to lowest sequence number
|
|
211
|
-
eventsIter = fetchEventsBackward(
|
|
267
|
+
eventsIter = fetchEventsBackward(ctx, opts, eventHandlerField, stateAddr, limit)
|
|
212
268
|
}
|
|
213
269
|
|
|
214
270
|
let topics
|
|
@@ -221,7 +277,7 @@ export async function* streamAptosLogs(
|
|
|
221
277
|
blockNumber: +ev.version,
|
|
222
278
|
transactionHash: opts?.versionAsHash
|
|
223
279
|
? `${ev.version}`
|
|
224
|
-
: (await getUserTxByVersion(provider, +ev.version)).hash,
|
|
280
|
+
: (await getUserTxByVersion(ctx.provider, +ev.version)).hash,
|
|
225
281
|
data: ev.data as Record<string, unknown>,
|
|
226
282
|
}
|
|
227
283
|
}
|
package/src/aptos/token.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Aptos } from '@aptos-labs/ts-sdk'
|
|
2
2
|
|
|
3
3
|
import type { TokenInfo } from '../chain.ts'
|
|
4
|
+
import { CCIPError } from '../errors/CCIPError.ts'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Retrieves token metadata (symbol and decimals) from Aptos.
|
|
@@ -152,5 +153,8 @@ export async function getTokenInfo(provider: Aptos, token: string): Promise<Toke
|
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
|
|
155
|
-
throw
|
|
156
|
+
throw CCIPError.from(
|
|
157
|
+
lastErr ?? `Could not view token info for ${token}`,
|
|
158
|
+
'TOKEN_POOL_INFO_NOT_FOUND',
|
|
159
|
+
)
|
|
156
160
|
}
|
package/src/aptos/types.ts
CHANGED
|
@@ -78,12 +78,12 @@ export function serializeExecutionReport(
|
|
|
78
78
|
): Uint8Array {
|
|
79
79
|
const message = execReport.message
|
|
80
80
|
return ExecutionReportCodec.serialize({
|
|
81
|
-
sourceChainSelector: message.
|
|
82
|
-
messageId: getBytes(message.
|
|
83
|
-
headerSourceChainSelector: message.
|
|
84
|
-
destChainSelector: message.
|
|
85
|
-
sequenceNumber: message.
|
|
86
|
-
nonce: message.
|
|
81
|
+
sourceChainSelector: message.sourceChainSelector,
|
|
82
|
+
messageId: getBytes(message.messageId),
|
|
83
|
+
headerSourceChainSelector: message.sourceChainSelector,
|
|
84
|
+
destChainSelector: message.destChainSelector,
|
|
85
|
+
sequenceNumber: message.sequenceNumber,
|
|
86
|
+
nonce: message.nonce,
|
|
87
87
|
sender: getAddressBytes(message.sender),
|
|
88
88
|
data: getBytes(message.data),
|
|
89
89
|
receiver: getAddressBytes(message.receiver),
|
package/src/chain.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { BytesLike } from 'ethers'
|
|
2
|
-
import type { PickDeep } from 'type-fest'
|
|
2
|
+
import type { PickDeep, SetOptional } from 'type-fest'
|
|
3
3
|
|
|
4
4
|
import type { UnsignedAptosTx } from './aptos/types.ts'
|
|
5
5
|
import { fetchCommitReport } from './commits.ts'
|
|
6
|
-
import
|
|
6
|
+
import { CCIPChainFamilyMismatchError, CCIPTransactionNotFinalizedError } from './errors/index.ts'
|
|
7
|
+
import type { UnsignedEVMTx } from './evm/types.ts'
|
|
7
8
|
import type {
|
|
8
9
|
EVMExtraArgsV1,
|
|
9
10
|
EVMExtraArgsV2,
|
|
@@ -13,6 +14,7 @@ import type {
|
|
|
13
14
|
} from './extra-args.ts'
|
|
14
15
|
import type { LeafHasher } from './hasher/common.ts'
|
|
15
16
|
import type { UnsignedSolanaTx } from './solana/types.ts'
|
|
17
|
+
import type { UnsignedTONTx } from './ton/types.ts'
|
|
16
18
|
import {
|
|
17
19
|
type AnyMessage,
|
|
18
20
|
type CCIPCommit,
|
|
@@ -43,9 +45,13 @@ export type LogFilter = {
|
|
|
43
45
|
/** Starting Unix timestamp (inclusive). */
|
|
44
46
|
startTime?: number
|
|
45
47
|
/** Ending block number (inclusive). */
|
|
46
|
-
endBlock?: number
|
|
47
|
-
/**
|
|
48
|
+
endBlock?: number | 'finalized' | 'latest'
|
|
49
|
+
/** Solana: optional hint txHash for end of iteration. */
|
|
48
50
|
endBefore?: string
|
|
51
|
+
/** watch mode: polls for new logs after fetching since start (required), until endBlock finality tag
|
|
52
|
+
* (e.g. endBlock=finalized polls only finalized logs); can be a promise to cancel loop
|
|
53
|
+
*/
|
|
54
|
+
watch?: boolean | Promise<unknown>
|
|
49
55
|
/** Contract address to filter logs by. */
|
|
50
56
|
address?: string
|
|
51
57
|
/** Topics to filter logs by. */
|
|
@@ -100,6 +106,7 @@ export type UnsignedTx = {
|
|
|
100
106
|
[ChainFamily.EVM]: UnsignedEVMTx
|
|
101
107
|
[ChainFamily.Solana]: UnsignedSolanaTx
|
|
102
108
|
[ChainFamily.Aptos]: UnsignedAptosTx
|
|
109
|
+
[ChainFamily.TON]: UnsignedTONTx
|
|
103
110
|
[ChainFamily.Sui]: never // TODO
|
|
104
111
|
}
|
|
105
112
|
|
|
@@ -117,7 +124,11 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
117
124
|
*/
|
|
118
125
|
constructor(network: NetworkInfo, { logger = console }: WithLogger = {}) {
|
|
119
126
|
if (network.family !== (this.constructor as ChainStatic).family)
|
|
120
|
-
throw new
|
|
127
|
+
throw new CCIPChainFamilyMismatchError(
|
|
128
|
+
this.constructor.name,
|
|
129
|
+
(this.constructor as ChainStatic).family,
|
|
130
|
+
network.family,
|
|
131
|
+
)
|
|
121
132
|
this.network = network as NetworkInfo<F>
|
|
122
133
|
this.logger = logger
|
|
123
134
|
}
|
|
@@ -132,7 +143,7 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
132
143
|
|
|
133
144
|
/**
|
|
134
145
|
* Fetch the timestamp of a given block
|
|
135
|
-
* @param block - block number or 'finalized'
|
|
146
|
+
* @param block - positive block number, negative finality depth or 'finalized' tag
|
|
136
147
|
* @returns timestamp of the block, in seconds
|
|
137
148
|
*/
|
|
138
149
|
abstract getBlockTimestamp(block: number | 'finalized'): Promise<number>
|
|
@@ -142,6 +153,49 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
142
153
|
* @returns generic transaction details
|
|
143
154
|
*/
|
|
144
155
|
abstract getTransaction(hash: string): Promise<ChainTransaction>
|
|
156
|
+
/**
|
|
157
|
+
* Confirm a log tx is finalized or wait for it to be finalized
|
|
158
|
+
* Throws if it isn't included (e.g. a reorg)
|
|
159
|
+
*/
|
|
160
|
+
async waitFinalized(
|
|
161
|
+
{
|
|
162
|
+
log,
|
|
163
|
+
tx,
|
|
164
|
+
}: SetOptional<
|
|
165
|
+
PickDeep<
|
|
166
|
+
CCIPRequest,
|
|
167
|
+
| `log.${'address' | 'blockNumber' | 'transactionHash' | 'topics' | 'tx.timestamp'}`
|
|
168
|
+
| 'tx.timestamp'
|
|
169
|
+
>,
|
|
170
|
+
'tx'
|
|
171
|
+
>,
|
|
172
|
+
finality: number | 'finalized' = 'finalized',
|
|
173
|
+
cancel$?: Promise<unknown>,
|
|
174
|
+
): Promise<true> {
|
|
175
|
+
const timestamp = log.tx?.timestamp ?? tx?.timestamp
|
|
176
|
+
if (!timestamp || Date.now() / 1e3 - timestamp > 60) {
|
|
177
|
+
// only try to fetch tx if request is old enough (>60s)
|
|
178
|
+
const [trans, finalizedTs] = await Promise.all([
|
|
179
|
+
this.getTransaction(log.transactionHash),
|
|
180
|
+
this.getBlockTimestamp(finality),
|
|
181
|
+
])
|
|
182
|
+
if (trans.timestamp <= finalizedTs) return true
|
|
183
|
+
}
|
|
184
|
+
for await (const l of this.getLogs({
|
|
185
|
+
address: log.address,
|
|
186
|
+
startBlock: log.blockNumber,
|
|
187
|
+
endBlock: finality,
|
|
188
|
+
topics: [log.topics[0]],
|
|
189
|
+
watch: cancel$ ?? true,
|
|
190
|
+
})) {
|
|
191
|
+
if (l.transactionHash === log.transactionHash) {
|
|
192
|
+
return true
|
|
193
|
+
} else if (l.blockNumber > log.blockNumber) {
|
|
194
|
+
break
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
throw new CCIPTransactionNotFinalizedError(log.transactionHash)
|
|
198
|
+
}
|
|
145
199
|
/**
|
|
146
200
|
* An async generator that yields logs based on the provided options.
|
|
147
201
|
* @param opts - Options object containing:
|
|
@@ -189,7 +243,7 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
189
243
|
abstract fetchAllMessagesInBatch<
|
|
190
244
|
R extends PickDeep<
|
|
191
245
|
CCIPRequest,
|
|
192
|
-
'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.
|
|
246
|
+
'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.sequenceNumber'
|
|
193
247
|
>,
|
|
194
248
|
>(
|
|
195
249
|
request: R,
|
|
@@ -374,8 +428,8 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
374
428
|
**/
|
|
375
429
|
async fetchCommitReport(
|
|
376
430
|
commitStore: string,
|
|
377
|
-
request: PickDeep<CCIPRequest, 'lane' | 'message.
|
|
378
|
-
hints?: { startBlock?: number
|
|
431
|
+
request: PickDeep<CCIPRequest, 'lane' | 'message.sequenceNumber' | 'tx.timestamp'>,
|
|
432
|
+
hints?: Pick<LogFilter, 'page' | 'watch'> & { startBlock?: number },
|
|
379
433
|
): Promise<CCIPCommit> {
|
|
380
434
|
return fetchCommitReport(this, commitStore, request, hints)
|
|
381
435
|
}
|
|
@@ -390,9 +444,9 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
390
444
|
*/
|
|
391
445
|
async *fetchExecutionReceipts(
|
|
392
446
|
offRamp: string,
|
|
393
|
-
request: PickDeep<CCIPRequest, 'lane' | 'message.
|
|
447
|
+
request: PickDeep<CCIPRequest, 'lane' | 'message.messageId' | 'tx.timestamp'>,
|
|
394
448
|
commit?: CCIPCommit,
|
|
395
|
-
hints?:
|
|
449
|
+
hints?: Pick<LogFilter, 'page' | 'watch'>,
|
|
396
450
|
): AsyncIterableIterator<CCIPExecution> {
|
|
397
451
|
const onlyLast = !commit?.log.blockNumber && !request.tx.timestamp // backwards
|
|
398
452
|
for await (const log of this.getLogs({
|
|
@@ -403,7 +457,7 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
403
457
|
...hints,
|
|
404
458
|
})) {
|
|
405
459
|
const receipt = (this.constructor as ChainStatic).decodeReceipt(log)
|
|
406
|
-
if (!receipt || receipt.messageId !== request.message.
|
|
460
|
+
if (!receipt || receipt.messageId !== request.message.messageId) continue
|
|
407
461
|
|
|
408
462
|
const timestamp = log.tx?.timestamp ?? (await this.getBlockTimestamp(log.blockNumber))
|
|
409
463
|
yield { receipt, log, timestamp }
|
|
@@ -514,6 +568,23 @@ export type ChainStatic<F extends ChainFamily = ChainFamily> = Function & {
|
|
|
514
568
|
* @returns Address in this chain family's format
|
|
515
569
|
*/
|
|
516
570
|
getAddress(bytes: BytesLike): string
|
|
571
|
+
/**
|
|
572
|
+
* Validates a transaction hash format for this chain family
|
|
573
|
+
*/
|
|
574
|
+
isTxHash(v: unknown): v is string
|
|
575
|
+
/**
|
|
576
|
+
* Format an address for human-friendly display.
|
|
577
|
+
* Defaults to getAddress if not overridden.
|
|
578
|
+
* @param address - Address string in any recognized format
|
|
579
|
+
* @returns Human-friendly address string for display
|
|
580
|
+
*/
|
|
581
|
+
formatAddress?(address: string): string
|
|
582
|
+
/**
|
|
583
|
+
* Format a transaction hash for human-friendly display.
|
|
584
|
+
* @param hash - Transaction hash string
|
|
585
|
+
* @returns Human-friendly hash string for display
|
|
586
|
+
*/
|
|
587
|
+
formatTxHash?(hash: string): string
|
|
517
588
|
/**
|
|
518
589
|
* Create a leaf hasher for this dest chain and lane
|
|
519
590
|
* @param lane - source, dest and onramp lane info
|
package/src/commits.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PickDeep } from 'type-fest'
|
|
2
2
|
|
|
3
|
-
import type { Chain, ChainStatic } from './chain.ts'
|
|
3
|
+
import type { Chain, ChainStatic, LogFilter } from './chain.ts'
|
|
4
|
+
import { CCIPCommitNotFoundError } from './errors/index.ts'
|
|
4
5
|
import { type CCIPCommit, type CCIPRequest, CCIPVersion } from './types.ts'
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -19,10 +20,10 @@ export async function fetchCommitReport(
|
|
|
19
20
|
commitStore: string,
|
|
20
21
|
{
|
|
21
22
|
lane,
|
|
22
|
-
message
|
|
23
|
+
message,
|
|
23
24
|
tx: { timestamp: requestTimestamp },
|
|
24
|
-
}: PickDeep<CCIPRequest, 'lane' | 'message.
|
|
25
|
-
hints?: { startBlock?: number
|
|
25
|
+
}: PickDeep<CCIPRequest, 'lane' | 'message.sequenceNumber' | 'tx.timestamp'>,
|
|
26
|
+
hints?: Pick<LogFilter, 'page' | 'watch'> & { startBlock?: number },
|
|
26
27
|
): Promise<CCIPCommit> {
|
|
27
28
|
for await (const log of dest.getLogs({
|
|
28
29
|
...hints,
|
|
@@ -30,14 +31,25 @@ export async function fetchCommitReport(
|
|
|
30
31
|
address: commitStore,
|
|
31
32
|
topics: [lane.version < CCIPVersion.V1_6 ? 'ReportAccepted' : 'CommitReportAccepted'],
|
|
32
33
|
})) {
|
|
33
|
-
const
|
|
34
|
-
if (!
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
const reports = (dest.constructor as ChainStatic).decodeCommits(log, lane)
|
|
35
|
+
if (!reports) continue
|
|
36
|
+
const validReports = reports.filter((r) => {
|
|
37
|
+
if (!r || r.maxSeqNr < message.sequenceNumber) return
|
|
38
|
+
// we could give up since we walk forward from some startBlock/startTime, but there might be some out-of-order logs
|
|
39
|
+
if (r.minSeqNr > message.sequenceNumber) return
|
|
40
|
+
return true
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
if (validReports.length === 0) continue
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
log,
|
|
47
|
+
report: validReports[0],
|
|
48
|
+
}
|
|
38
49
|
}
|
|
39
50
|
|
|
40
|
-
throw new
|
|
41
|
-
|
|
51
|
+
throw new CCIPCommitNotFoundError(
|
|
52
|
+
hints?.startBlock ?? String(requestTimestamp),
|
|
53
|
+
message.sequenceNumber,
|
|
42
54
|
)
|
|
43
55
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { CCIPErrorCode } from './codes.ts'
|
|
2
|
+
import { getDefaultRecovery } from './recovery.ts'
|
|
3
|
+
|
|
4
|
+
/** Options for CCIPError constructor. */
|
|
5
|
+
export interface CCIPErrorOptions {
|
|
6
|
+
/** Original error (ES2022 cause). */
|
|
7
|
+
cause?: Error
|
|
8
|
+
/** Structured context (IDs, addresses). */
|
|
9
|
+
context?: Record<string, unknown>
|
|
10
|
+
/** True if retry may succeed. */
|
|
11
|
+
isTransient?: boolean
|
|
12
|
+
/** Retry delay in ms. */
|
|
13
|
+
retryAfterMs?: number
|
|
14
|
+
/** Recovery suggestion. */
|
|
15
|
+
recovery?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Base error class for CCIP SDK.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* if (CCIPError.isCCIPError(error) && error.isTransient) {
|
|
24
|
+
* await sleep(error.retryAfterMs ?? 5000)
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class CCIPError extends Error {
|
|
29
|
+
/** Brand for cross-module identification (dual package hazard). */
|
|
30
|
+
readonly _isCCIPError = true as const
|
|
31
|
+
/** Machine-readable error code. */
|
|
32
|
+
readonly code: CCIPErrorCode
|
|
33
|
+
/** Structured context (IDs, addresses). */
|
|
34
|
+
readonly context: Record<string, unknown>
|
|
35
|
+
/** True if retry may succeed. */
|
|
36
|
+
readonly isTransient: boolean
|
|
37
|
+
/** Retry delay in ms. */
|
|
38
|
+
readonly retryAfterMs?: number
|
|
39
|
+
/** Recovery suggestion. */
|
|
40
|
+
readonly recovery?: string
|
|
41
|
+
|
|
42
|
+
override readonly name: string = 'CCIPError'
|
|
43
|
+
|
|
44
|
+
/** Creates CCIPError with code, message, and options. */
|
|
45
|
+
constructor(code: CCIPErrorCode, message: string, options?: CCIPErrorOptions) {
|
|
46
|
+
super(message, { cause: options?.cause })
|
|
47
|
+
Object.setPrototypeOf(this, new.target.prototype)
|
|
48
|
+
|
|
49
|
+
this.code = code
|
|
50
|
+
this.context = options?.context ?? {}
|
|
51
|
+
this.isTransient = options?.isTransient ?? false
|
|
52
|
+
this.retryAfterMs = options?.retryAfterMs
|
|
53
|
+
this.recovery = options?.recovery ?? getDefaultRecovery(code)
|
|
54
|
+
|
|
55
|
+
Error.captureStackTrace?.(this, this.constructor)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Type guard. Prefer over instanceof (handles dual package hazard). */
|
|
59
|
+
static isCCIPError(error: unknown): error is CCIPError {
|
|
60
|
+
return error instanceof CCIPError || !!(error as { _isCCIPError?: boolean })?._isCCIPError
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Wrap unknown catch value in CCIPError. */
|
|
64
|
+
static from(error: unknown, code?: CCIPErrorCode): CCIPError {
|
|
65
|
+
if (error instanceof CCIPError) return error
|
|
66
|
+
if (error instanceof Error) {
|
|
67
|
+
return new CCIPError(code ?? 'UNKNOWN', error.message, { cause: error })
|
|
68
|
+
}
|
|
69
|
+
return new CCIPError(code ?? 'UNKNOWN', String(error))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Serialize for logging (JSON.stringify loses non-enumerable props). */
|
|
73
|
+
toJSON(): Record<string, unknown> {
|
|
74
|
+
return {
|
|
75
|
+
name: this.name,
|
|
76
|
+
message: this.message,
|
|
77
|
+
code: this.code,
|
|
78
|
+
context: this.context,
|
|
79
|
+
isTransient: this.isTransient,
|
|
80
|
+
retryAfterMs: this.retryAfterMs,
|
|
81
|
+
recovery: this.recovery,
|
|
82
|
+
stack: this.stack,
|
|
83
|
+
cause: this.cause instanceof Error ? this.cause.message : this.cause,
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|