damm-sdk 1.4.18 → 1.4.21
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/dist/index.cjs +689 -46
- package/dist/index.cjs.map +18 -3
- package/dist/index.js +47397 -40297
- package/dist/index.js.map +134 -72
- package/dist/integrations/ccip/ccip.router.abi.d.ts +85 -0
- package/dist/integrations/ccip/ccip.router.abi.d.ts.map +1 -0
- package/dist/integrations/ccip/ccip.router.d.ts +72 -0
- package/dist/integrations/ccip/ccip.router.d.ts.map +1 -0
- package/dist/integrations/ccip/index.d.ts +3 -0
- package/dist/integrations/ccip/index.d.ts.map +1 -0
- package/dist/integrations/index.d.ts +2 -0
- package/dist/integrations/index.d.ts.map +1 -1
- package/dist/integrations/wormhole/axelar.gmp.api.d.ts +47 -0
- package/dist/integrations/wormhole/axelar.gmp.api.d.ts.map +1 -0
- package/dist/integrations/wormhole/executor.quote.api.d.ts +100 -0
- package/dist/integrations/wormhole/executor.quote.api.d.ts.map +1 -0
- package/dist/integrations/wormhole/gmp.manager.abi.d.ts +32 -0
- package/dist/integrations/wormhole/gmp.manager.abi.d.ts.map +1 -0
- package/dist/integrations/wormhole/gmp.manager.d.ts +65 -0
- package/dist/integrations/wormhole/gmp.manager.d.ts.map +1 -0
- package/dist/integrations/wormhole/index.d.ts +10 -0
- package/dist/integrations/wormhole/index.d.ts.map +1 -0
- package/dist/integrations/wormhole/wormhole.multi.ntt.abi.d.ts +101 -0
- package/dist/integrations/wormhole/wormhole.multi.ntt.abi.d.ts.map +1 -0
- package/dist/integrations/wormhole/wormhole.multi.ntt.d.ts +149 -0
- package/dist/integrations/wormhole/wormhole.multi.ntt.d.ts.map +1 -0
- package/dist/integrations/wormhole/wormhole.scan.api.d.ts +56 -0
- package/dist/integrations/wormhole/wormhole.scan.api.d.ts.map +1 -0
- package/dist/integrations/wormhole/wormhole.transceiver.abi.d.ts +23 -0
- package/dist/integrations/wormhole/wormhole.transceiver.abi.d.ts.map +1 -0
- package/dist/integrations/wormhole/wormhole.transceiver.d.ts +28 -0
- package/dist/integrations/wormhole/wormhole.transceiver.d.ts.map +1 -0
- package/package.json +3 -2
- package/src/integrations/ccip/ccip.router.abi.ts +62 -0
- package/src/integrations/ccip/ccip.router.ts +172 -0
- package/src/integrations/ccip/index.ts +19 -0
- package/src/integrations/index.ts +2 -0
- package/src/integrations/wormhole/axelar.gmp.api.ts +85 -0
- package/src/integrations/wormhole/executor.quote.api.ts +182 -0
- package/src/integrations/wormhole/gmp.manager.abi.ts +26 -0
- package/src/integrations/wormhole/gmp.manager.ts +129 -0
- package/src/integrations/wormhole/index.ts +68 -0
- package/src/integrations/wormhole/wormhole.multi.ntt.abi.ts +68 -0
- package/src/integrations/wormhole/wormhole.multi.ntt.ts +259 -0
- package/src/integrations/wormhole/wormhole.scan.api.ts +95 -0
- package/src/integrations/wormhole/wormhole.transceiver.abi.ts +20 -0
- package/src/integrations/wormhole/wormhole.transceiver.ts +46 -0
- package/src/lib/contractsRegistry.json +6 -2
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
import type { Call, HexString, Unwrapable } from "../../types";
|
|
3
|
+
/**
|
|
4
|
+
* Wormhole uint16 chain IDs.
|
|
5
|
+
*
|
|
6
|
+
* Wormhole uses its own chain-ID space distinct from EVM chain IDs.
|
|
7
|
+
* Reference: https://wormhole.com/docs/products/reference/chain-ids/
|
|
8
|
+
*/
|
|
9
|
+
export declare const WORMHOLE_CHAIN_IDS: Readonly<Record<number, number>>;
|
|
10
|
+
/**
|
|
11
|
+
* Resolve the Wormhole chain ID for an EVM chain ID.
|
|
12
|
+
* @throws if the chain has no Wormhole chain ID registered.
|
|
13
|
+
*/
|
|
14
|
+
export declare const getWormholeChainId: (chainId: number) => number;
|
|
15
|
+
/**
|
|
16
|
+
* Left-pad a 20-byte address to bytes32 (the standard ABI encoding used
|
|
17
|
+
* by Wormhole NTT for `recipient` / `refundAddress` fields).
|
|
18
|
+
*/
|
|
19
|
+
export declare const addressToBytes32: (addr: Address) => HexString;
|
|
20
|
+
export type ExecutorArgs = Readonly<{
|
|
21
|
+
/** Relay fee paid to the executor (forwarded as msg.value). */
|
|
22
|
+
value: bigint;
|
|
23
|
+
/** Where the executor refunds unused gas on the SOURCE chain. */
|
|
24
|
+
refundAddress: Address;
|
|
25
|
+
/** Signed quote bytes from the executor API. */
|
|
26
|
+
signedQuote: HexString;
|
|
27
|
+
/** Relay instructions bytes (see buildRelayInstructions). */
|
|
28
|
+
instructions: HexString;
|
|
29
|
+
}>;
|
|
30
|
+
export type FeeArgs = Readonly<{
|
|
31
|
+
/** App-level fee in deci-basis points (10_000 = 100%). Always 0 for DAMM. */
|
|
32
|
+
dbps: number;
|
|
33
|
+
/** Fee recipient. Irrelevant when dbps = 0. */
|
|
34
|
+
payee: Address;
|
|
35
|
+
}>;
|
|
36
|
+
export type WormholeTransferArgs = Readonly<{
|
|
37
|
+
/** MultiTokenNTT manager address on the source chain. */
|
|
38
|
+
multiTokenNtt: Address;
|
|
39
|
+
/** ERC20 token to bridge (e.g. WETH). */
|
|
40
|
+
token: Address;
|
|
41
|
+
/** Amount to bridge (token smallest unit). */
|
|
42
|
+
amount: bigint;
|
|
43
|
+
/** Destination chain (Wormhole chain ID, not EVM). */
|
|
44
|
+
recipientChain: number;
|
|
45
|
+
/** Destination address (bytes32, left-padded). Use addressToBytes32(). */
|
|
46
|
+
recipient: HexString;
|
|
47
|
+
/** Top-level refund address on the DESTINATION chain (bytes32). */
|
|
48
|
+
refundAddress: HexString;
|
|
49
|
+
/** Transceiver instructions. Pass "0x" for defaults. */
|
|
50
|
+
transceiverInstructions: HexString;
|
|
51
|
+
executorArgs: ExecutorArgs;
|
|
52
|
+
feeArgs: FeeArgs;
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* Encode calldata for `MultiNTTWithExecutor.transfer(...)`.
|
|
56
|
+
*/
|
|
57
|
+
export declare const WormholeTransferCalldata: (args: WormholeTransferArgs) => HexString;
|
|
58
|
+
/**
|
|
59
|
+
* Build a Call for `MultiNTTWithExecutor.transfer(...)`.
|
|
60
|
+
*
|
|
61
|
+
* `msg.value` = `executorArgs.value` (Executor relay fee) + any per-transceiver
|
|
62
|
+
* delivery fees required by the underlying `MultiTokenNTT` (e.g. Axelar's
|
|
63
|
+
* gateway fee on the Monad ↔ Ethereum lane).
|
|
64
|
+
*
|
|
65
|
+
* Pass `transceiverFee` when the `MultiTokenNTT` uses a paid transceiver in
|
|
66
|
+
* addition to Wormhole's guardian signing. Query the exact amount via
|
|
67
|
+
* `GmpManager.quoteDeliveryPrice(recipientChain, transceiverInstructions)`
|
|
68
|
+
* (see `GmpManagerQuoteDeliveryPriceCalldata`).
|
|
69
|
+
*/
|
|
70
|
+
export declare const wormholeTransferTrx: ({ wrapperAddress, args, transceiverFee, }: {
|
|
71
|
+
/** MultiNTTWithExecutor address on the source chain. */
|
|
72
|
+
wrapperAddress: Address;
|
|
73
|
+
args: WormholeTransferArgs;
|
|
74
|
+
/** Extra native token required by paid transceivers (e.g. Axelar). */
|
|
75
|
+
transceiverFee?: bigint | undefined;
|
|
76
|
+
}) => Unwrapable<Call>;
|
|
77
|
+
/**
|
|
78
|
+
* Default `gasLimit` for `MultiTokenNTT` redemption on the destination chain.
|
|
79
|
+
*
|
|
80
|
+
* MultiNTT redemption is expensive because it:
|
|
81
|
+
* (a) verifies the Wormhole VAA (guardian signatures + replay protection)
|
|
82
|
+
* (b) verifies the sibling transceiver's attestation (2/2 check)
|
|
83
|
+
* (c) executes the token mint/transfer on the destination `MultiTokenNTT`
|
|
84
|
+
*
|
|
85
|
+
* Empirically, successful Monad ↔ Mainnet transfers use ~650_000 gas; manual
|
|
86
|
+
* `receiveMessage` calls land in ~330_000. Default is 1_000_000 to leave
|
|
87
|
+
* headroom for future protocol upgrades and any per-block variance — the
|
|
88
|
+
* extra cost is tiny (~$0.20 per Monad→Mainnet bridge at typical prices)
|
|
89
|
+
* and eliminates `evm_simulation_gas_too_low` rejections from the Executor.
|
|
90
|
+
*
|
|
91
|
+
* Note: this is gas UNITS, not gas PRICE. It does not need to track network
|
|
92
|
+
* congestion — destination-chain gas usage is deterministic. What network
|
|
93
|
+
* spikes affect is the COST of providing this budget; that's bounded
|
|
94
|
+
* separately by the `etherWithinAllowance` permission cap in the kit.
|
|
95
|
+
*
|
|
96
|
+
* Override per-call via `buildRelayInstructions({ gasLimit: N })` if you have
|
|
97
|
+
* empirical data showing a different value is appropriate for your asset/lane.
|
|
98
|
+
*/
|
|
99
|
+
export declare const DEFAULT_NTT_REDEMPTION_GAS_LIMIT = 1000000n;
|
|
100
|
+
/**
|
|
101
|
+
* Encode `GasInstruction` relay instructions for the executor.
|
|
102
|
+
*
|
|
103
|
+
* Format (per Wormhole SDK): `0x01` (version) || uint128 gasLimit || uint128 msgValue
|
|
104
|
+
* - `gasLimit`: gas units the executor should provide when redeeming on the destination
|
|
105
|
+
* - `msgValue`: native token (in wei on destination) to forward with the redemption call
|
|
106
|
+
*
|
|
107
|
+
* Default `gasLimit` is `DEFAULT_NTT_REDEMPTION_GAS_LIMIT` (650k), calibrated
|
|
108
|
+
* for `MultiTokenNTT` with a 2/2 transceiver stack. Override only if you know
|
|
109
|
+
* the destination chain's redemption consumes less.
|
|
110
|
+
*/
|
|
111
|
+
export declare const buildRelayInstructions: ({ gasLimit, msgValue, }?: {
|
|
112
|
+
gasLimit?: bigint | undefined;
|
|
113
|
+
msgValue?: bigint | undefined;
|
|
114
|
+
}) => HexString;
|
|
115
|
+
/**
|
|
116
|
+
* Encode calldata for the view function `calculateFee(amount, dbps)`.
|
|
117
|
+
* Useful to query the dbps-based fee charged by the wrapper off-chain.
|
|
118
|
+
*/
|
|
119
|
+
export declare const WormholeCalculateFeeCalldata: ({ amount, dbps }: {
|
|
120
|
+
amount: bigint;
|
|
121
|
+
dbps: number;
|
|
122
|
+
}) => HexString;
|
|
123
|
+
/**
|
|
124
|
+
* Compose a `WormholeTransferArgs` where recipient and refund addresses
|
|
125
|
+
* default to the same avatar (the Safe on both chains share an address).
|
|
126
|
+
*
|
|
127
|
+
* This matches the permission constraint in Our-DeFi-Kit's
|
|
128
|
+
* `WormholeBridgingPermissions`, which scopes `recipient`, top-level
|
|
129
|
+
* `refundAddress`, and `executorArgs.refundAddress` all to `c.avatar`.
|
|
130
|
+
*/
|
|
131
|
+
export declare const buildWormholeTransferArgsFromAvatar: ({ multiTokenNtt, token, amount, recipientChain, avatar, relayFee, signedQuote, relayInstructions, transceiverInstructions, dbps, payee, }: {
|
|
132
|
+
multiTokenNtt: Address;
|
|
133
|
+
token: Address;
|
|
134
|
+
amount: bigint;
|
|
135
|
+
/** Wormhole chain ID (not EVM). */
|
|
136
|
+
recipientChain: number;
|
|
137
|
+
/** The Safe address (same on source + destination). */
|
|
138
|
+
avatar: Address;
|
|
139
|
+
/** Native relay fee to forward (from signed quote estimatedCost). */
|
|
140
|
+
relayFee: bigint;
|
|
141
|
+
signedQuote: HexString;
|
|
142
|
+
relayInstructions: HexString;
|
|
143
|
+
transceiverInstructions?: `0x${string}` | undefined;
|
|
144
|
+
/** Defaults to 0 — DAMM never charges a skim fee. */
|
|
145
|
+
dbps?: number | undefined;
|
|
146
|
+
/** Defaults to the zero address when dbps = 0 (irrelevant). */
|
|
147
|
+
payee?: `0x${string}` | undefined;
|
|
148
|
+
}) => WormholeTransferArgs;
|
|
149
|
+
//# sourceMappingURL=wormhole.multi.ntt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wormhole.multi.ntt.d.ts","sourceRoot":"","sources":["../../../src/integrations/wormhole/wormhole.multi.ntt.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK/D;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAG9D,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,kBAAkB,YAAa,MAAM,KAAG,MAMpD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,SAAU,OAAO,KAAG,SAA+D,CAAC;AAIjH,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAChC,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,aAAa,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,WAAW,EAAE,SAAS,CAAC;IACvB,6DAA6D;IAC7D,YAAY,EAAE,SAAS,CAAC;CAC3B,CAAC,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC;IAC3B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,KAAK,EAAE,OAAO,CAAC;CAClB,CAAC,CAAC;AAIH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IACxC,yDAAyD;IACzD,aAAa,EAAE,OAAO,CAAC;IACvB,yCAAyC;IACzC,KAAK,EAAE,OAAO,CAAC;IACf,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,cAAc,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,SAAS,EAAE,SAAS,CAAC;IACrB,mEAAmE;IACnE,aAAa,EAAE,SAAS,CAAC;IACzB,wDAAwD;IACxD,uBAAuB,EAAE,SAAS,CAAC;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;CACpB,CAAC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,wBAAwB,SAAU,oBAAoB,KAAG,SAoBrE,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB;IAK5B,wDAAwD;oBACxC,OAAO;UACjB,oBAAoB;IAC1B,sEAAsE;;MAEtE,WAAW,IAAI,CAOlB,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,gCAAgC,WAAa,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB;;;MAM1B,SAQR,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,4BAA4B;YAAgC,MAAM;UAAQ,MAAM;MAAK,SAEjG,CAAC;AAIF;;;;;;;GAOG;AACH,eAAO,MAAM,mCAAmC;mBAa7B,OAAO;WACf,OAAO;YACN,MAAM;IACd,mCAAmC;oBACnB,MAAM;IACtB,uDAAuD;YAC/C,OAAO;IACf,qEAAqE;cAC3D,MAAM;iBACH,SAAS;uBACH,SAAS;;IAE5B,qDAAqD;;IAErD,+DAA+D;;MAE/D,oBAqBH,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client for the WormholeScan public API — used to fetch the signed VAA
|
|
3
|
+
* emitted by a source-chain transceiver for a given cross-chain message.
|
|
4
|
+
*
|
|
5
|
+
* Endpoints:
|
|
6
|
+
* - Mainnet: https://api.wormholescan.io
|
|
7
|
+
* - Testnet: https://api.testnet.wormholescan.io
|
|
8
|
+
*
|
|
9
|
+
* API reference: https://docs.wormhole.com/wormhole/reference/api-docs/wormholescan
|
|
10
|
+
*/
|
|
11
|
+
import type { HexString } from "../../types";
|
|
12
|
+
export declare const WORMHOLESCAN_API_MAINNET: "https://api.wormholescan.io";
|
|
13
|
+
export declare const WORMHOLESCAN_API_TESTNET: "https://api.testnet.wormholescan.io";
|
|
14
|
+
export type WormholeNetworkEnv = "Mainnet" | "Testnet";
|
|
15
|
+
export declare const getWormholeScanApiUrl: (network?: WormholeNetworkEnv) => string;
|
|
16
|
+
/**
|
|
17
|
+
* Convert a 20-byte address to the 64-char (32-byte) padded lowercase hex
|
|
18
|
+
* format WormholeScan expects for the `emitter` URL segment.
|
|
19
|
+
*/
|
|
20
|
+
export declare const normalizeEmitterForVaaLookup: (emitter: HexString) => string;
|
|
21
|
+
export type VaaLookupArgs = Readonly<{
|
|
22
|
+
/** Wormhole chain ID of the source chain (NOT EVM chainId). */
|
|
23
|
+
emitterChain: number;
|
|
24
|
+
/** Source-chain transceiver address — 20 or 32 byte hex. */
|
|
25
|
+
emitterAddress: HexString;
|
|
26
|
+
/** Sequence number emitted by the Wormhole core bridge. */
|
|
27
|
+
sequence: number | bigint;
|
|
28
|
+
}>;
|
|
29
|
+
export type VaaLookupResponse = Readonly<{
|
|
30
|
+
sequence: number;
|
|
31
|
+
id: string;
|
|
32
|
+
emitterChain: number;
|
|
33
|
+
emitterAddr: string;
|
|
34
|
+
emitterNativeAddr: string;
|
|
35
|
+
/** Base64-encoded signed VAA bytes. */
|
|
36
|
+
vaa: string;
|
|
37
|
+
timestamp?: string;
|
|
38
|
+
txHash?: string;
|
|
39
|
+
digest?: string;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Fetch the signed VAA for a given (chain, emitter, sequence).
|
|
43
|
+
*
|
|
44
|
+
* Throws if WormholeScan returns any non-2xx response (including 404, which
|
|
45
|
+
* happens during the brief window after the source tx confirms but before
|
|
46
|
+
* guardians have signed). Callers that want to poll should wrap this in a
|
|
47
|
+
* retry loop — letting the caller decide whether a 404 is a transient
|
|
48
|
+
* "not-yet-signed" or a permanent "wrong inputs" condition.
|
|
49
|
+
*/
|
|
50
|
+
export declare const fetchWormholeVAA: (args: VaaLookupArgs, network?: WormholeNetworkEnv) => Promise<VaaLookupResponse>;
|
|
51
|
+
/**
|
|
52
|
+
* Decode a base64 VAA string into 0x-prefixed hex bytes, ready for
|
|
53
|
+
* `WormholeReceiveMessageCalldata`.
|
|
54
|
+
*/
|
|
55
|
+
export declare const decodeVaaBase64: (base64: string) => HexString;
|
|
56
|
+
//# sourceMappingURL=wormhole.scan.api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wormhole.scan.api.d.ts","sourceRoot":"","sources":["../../../src/integrations/wormhole/wormhole.scan.api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,eAAO,MAAM,wBAAwB,+BAAyC,CAAC;AAC/E,eAAO,MAAM,wBAAwB,uCAAiD,CAAC;AAEvF,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,SAAS,CAAC;AAEvD,eAAO,MAAM,qBAAqB,aAAa,kBAAkB,KAAe,MACD,CAAC;AAIhF;;;GAGG;AACH,eAAO,MAAM,4BAA4B,YAAa,SAAS,KAAG,MAOjE,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACjC,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,cAAc,EAAE,SAAS,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,SACnB,aAAa,YACV,kBAAkB,KAC5B,QAAQ,iBAAiB,CAgB3B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,WAAY,MAAM,KAAG,SACiC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal ABI for Wormhole's `GenericWormholeTransceiver` — the destination-side
|
|
3
|
+
* contract that verifies a Wormhole VAA and forwards it as an attestation to
|
|
4
|
+
* the `GmpManager` so a pending cross-chain message can be executed.
|
|
5
|
+
*
|
|
6
|
+
* Mainnet: 0x9D0eADF3fc10380C4D2F5ba79499C6194549C7D2
|
|
7
|
+
* Monad: 0x1a0f31492Ca69DF6A82906Ce88613AeCD9245C44
|
|
8
|
+
*
|
|
9
|
+
* Only the one function we need for manual recovery: `receiveMessage`.
|
|
10
|
+
* The call is permissionless — any EOA with enough gas can deliver a VAA.
|
|
11
|
+
*/
|
|
12
|
+
declare const _default: readonly [{
|
|
13
|
+
readonly inputs: readonly [{
|
|
14
|
+
readonly name: "encodedMessage";
|
|
15
|
+
readonly type: "bytes";
|
|
16
|
+
}];
|
|
17
|
+
readonly name: "receiveMessage";
|
|
18
|
+
readonly outputs: readonly [];
|
|
19
|
+
readonly stateMutability: "nonpayable";
|
|
20
|
+
readonly type: "function";
|
|
21
|
+
}];
|
|
22
|
+
export default _default;
|
|
23
|
+
//# sourceMappingURL=wormhole.transceiver.abi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wormhole.transceiver.abi.d.ts","sourceRoot":"","sources":["../../../src/integrations/wormhole/wormhole.transceiver.abi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;;;;;;;;;;;AACH,wBAQW"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
import type { Call, HexString, Unwrapable } from "../../types";
|
|
3
|
+
/**
|
|
4
|
+
* Encode calldata for `GenericWormholeTransceiver.receiveMessage(bytes vaa)`.
|
|
5
|
+
*
|
|
6
|
+
* Use this to manually deliver a Wormhole VAA to the destination transceiver
|
|
7
|
+
* when auto-relay has failed (e.g. Executor pre-flight sim rejected the gas
|
|
8
|
+
* quote and aborted). The transceiver verifies the VAA's guardian signatures
|
|
9
|
+
* and forwards the attestation to the `GmpManager`; once the 2/2 threshold is
|
|
10
|
+
* met with the sibling transceiver (e.g. Axelar), `executeMsg` fires
|
|
11
|
+
* automatically in the same transaction.
|
|
12
|
+
*/
|
|
13
|
+
export declare const WormholeReceiveMessageCalldata: ({ vaa }: {
|
|
14
|
+
vaa: HexString;
|
|
15
|
+
}) => HexString;
|
|
16
|
+
/**
|
|
17
|
+
* Build a Call for manually delivering a VAA to the Wormhole transceiver.
|
|
18
|
+
*
|
|
19
|
+
* The call is permissionless (any EOA works), takes no value, and is safe to
|
|
20
|
+
* retry — the transceiver rejects duplicates.
|
|
21
|
+
*/
|
|
22
|
+
export declare const wormholeReceiveMessageTrx: ({ transceiverAddress, vaa, }: {
|
|
23
|
+
/** `GenericWormholeTransceiver` address on the destination chain. */
|
|
24
|
+
transceiverAddress: Address;
|
|
25
|
+
/** The signed VAA bytes, as fetched from WormholeScan. */
|
|
26
|
+
vaa: HexString;
|
|
27
|
+
}) => Unwrapable<Call>;
|
|
28
|
+
//# sourceMappingURL=wormhole.transceiver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wormhole.transceiver.d.ts","sourceRoot":"","sources":["../../../src/integrations/wormhole/wormhole.transceiver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAO/D;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B;SAAoB,SAAS;MAAK,SAE5E,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;IAIlC,qEAAqE;wBACjD,OAAO;IAC3B,0DAA0D;SACrD,SAAS;MACd,WAAW,IAAI,CAOlB,CAAC"}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"main": "./dist/index.cjs",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"version": "1.4.
|
|
7
|
+
"version": "1.4.21",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
10
10
|
"src",
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "rm -rf ./dist && bun build ./src/index.ts --outdir ./dist --entry-naming index.js --format esm --sourcemap=external && bun build ./src/index.ts --outdir ./dist --entry-naming index.cjs --format cjs --sourcemap=external && bun tsc --project tsconfig.json",
|
|
22
|
+
"verify:dist": "bun run scripts/verify-dist.ts",
|
|
22
23
|
"fmt": "prettier --write . && forge fmt",
|
|
23
|
-
"release": "bun run fmt && bun run build && npm publish --tag latest"
|
|
24
|
+
"release": "bun run fmt && bun run build && bun run verify:dist && npm publish --tag latest"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
27
|
"@types/bun": "latest",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal ABI for Chainlink CCIP Router contract.
|
|
3
|
+
* Only includes functions needed for bridge operations.
|
|
4
|
+
*
|
|
5
|
+
* Full contract: https://etherscan.io/address/0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D
|
|
6
|
+
*/
|
|
7
|
+
export default [
|
|
8
|
+
{
|
|
9
|
+
inputs: [
|
|
10
|
+
{ name: "destinationChainSelector", type: "uint64" },
|
|
11
|
+
{
|
|
12
|
+
name: "message",
|
|
13
|
+
type: "tuple",
|
|
14
|
+
components: [
|
|
15
|
+
{ name: "receiver", type: "bytes" },
|
|
16
|
+
{ name: "data", type: "bytes" },
|
|
17
|
+
{
|
|
18
|
+
name: "tokenAmounts",
|
|
19
|
+
type: "tuple[]",
|
|
20
|
+
components: [
|
|
21
|
+
{ name: "token", type: "address" },
|
|
22
|
+
{ name: "amount", type: "uint256" },
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
{ name: "feeToken", type: "address" },
|
|
26
|
+
{ name: "extraArgs", type: "bytes" },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
name: "ccipSend",
|
|
31
|
+
outputs: [{ name: "messageId", type: "bytes32" }],
|
|
32
|
+
stateMutability: "payable",
|
|
33
|
+
type: "function",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
inputs: [
|
|
37
|
+
{ name: "destinationChainSelector", type: "uint64" },
|
|
38
|
+
{
|
|
39
|
+
name: "message",
|
|
40
|
+
type: "tuple",
|
|
41
|
+
components: [
|
|
42
|
+
{ name: "receiver", type: "bytes" },
|
|
43
|
+
{ name: "data", type: "bytes" },
|
|
44
|
+
{
|
|
45
|
+
name: "tokenAmounts",
|
|
46
|
+
type: "tuple[]",
|
|
47
|
+
components: [
|
|
48
|
+
{ name: "token", type: "address" },
|
|
49
|
+
{ name: "amount", type: "uint256" },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{ name: "feeToken", type: "address" },
|
|
53
|
+
{ name: "extraArgs", type: "bytes" },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
name: "getFee",
|
|
58
|
+
outputs: [{ name: "fee", type: "uint256" }],
|
|
59
|
+
stateMutability: "view",
|
|
60
|
+
type: "function",
|
|
61
|
+
},
|
|
62
|
+
] as const;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { ethers } from "ethers";
|
|
2
|
+
import ccipRouterAbi from "./ccip.router.abi";
|
|
3
|
+
import type { Call, HexString, Unwrapable } from "../../types";
|
|
4
|
+
import { createCall } from "../../types";
|
|
5
|
+
import type { Address } from "viem";
|
|
6
|
+
|
|
7
|
+
const ccipRouterInterface = new ethers.utils.Interface(ccipRouterAbi as any);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* CCIP chain selectors (uint64).
|
|
11
|
+
* Source: https://docs.chain.link/ccip/directory/mainnet
|
|
12
|
+
* Verified on-chain 2026-04-13 via typeAndVersion() on each Router.
|
|
13
|
+
*/
|
|
14
|
+
export const CCIP_CHAIN_SELECTORS: Readonly<Record<number, string>> = Object.freeze({
|
|
15
|
+
1: "5009297550715157269", // Mainnet
|
|
16
|
+
42161: "4949039107694359620", // Arbitrum
|
|
17
|
+
8453: "15971525489660198786", // Base
|
|
18
|
+
10: "3734403246176062136", // Optimism
|
|
19
|
+
137: "4051577828743386545", // Polygon
|
|
20
|
+
56: "11344663589394136015", // BSC
|
|
21
|
+
143: "8481857512324358265", // Monad
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get the CCIP chain selector for a given chain ID.
|
|
26
|
+
* @throws if the chain is not supported
|
|
27
|
+
*/
|
|
28
|
+
export const getCCIPChainSelector = (chainId: number): string => {
|
|
29
|
+
const selector = CCIP_CHAIN_SELECTORS[chainId];
|
|
30
|
+
if (!selector) {
|
|
31
|
+
throw new Error(`CCIP: No chain selector for chainId ${chainId}`);
|
|
32
|
+
}
|
|
33
|
+
return selector;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// ─── EVM2AnyMessage struct ───────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
export type CCIPTokenAmount = Readonly<{
|
|
39
|
+
token: Address;
|
|
40
|
+
amount: bigint;
|
|
41
|
+
}>;
|
|
42
|
+
|
|
43
|
+
export type EVM2AnyMessage = Readonly<{
|
|
44
|
+
/** abi.encode(destinationAddress) */
|
|
45
|
+
receiver: HexString;
|
|
46
|
+
/** Empty (0x) for token-only transfers */
|
|
47
|
+
data: HexString;
|
|
48
|
+
/** Tokens to bridge */
|
|
49
|
+
tokenAmounts: readonly CCIPTokenAmount[];
|
|
50
|
+
/** address(0) = pay fee in native ETH/MON */
|
|
51
|
+
feeToken: Address;
|
|
52
|
+
/** Extra args (0x for defaults) */
|
|
53
|
+
extraArgs: HexString;
|
|
54
|
+
}>;
|
|
55
|
+
|
|
56
|
+
// ─── getFee ──────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
export type GetFeeArgs = Readonly<{
|
|
59
|
+
destinationChainSelector: string;
|
|
60
|
+
message: EVM2AnyMessage;
|
|
61
|
+
}>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Encode calldata for Router.getFee(destinationChainSelector, message).
|
|
65
|
+
* Use this to quote the CCIP fee via an RPC call.
|
|
66
|
+
*/
|
|
67
|
+
export const CCIPGetFeeCalldata = (args: GetFeeArgs): HexString => {
|
|
68
|
+
return ccipRouterInterface.encodeFunctionData("getFee", [
|
|
69
|
+
args.destinationChainSelector,
|
|
70
|
+
{
|
|
71
|
+
receiver: args.message.receiver,
|
|
72
|
+
data: args.message.data,
|
|
73
|
+
tokenAmounts: args.message.tokenAmounts.map((t) => ({
|
|
74
|
+
token: t.token,
|
|
75
|
+
amount: t.amount,
|
|
76
|
+
})),
|
|
77
|
+
feeToken: args.message.feeToken,
|
|
78
|
+
extraArgs: args.message.extraArgs,
|
|
79
|
+
},
|
|
80
|
+
]) as HexString;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Build a Call for Router.getFee (read-only, value=0).
|
|
85
|
+
*/
|
|
86
|
+
export const CCIPGetFeeTrx = ({
|
|
87
|
+
routerAddress,
|
|
88
|
+
args,
|
|
89
|
+
}: {
|
|
90
|
+
routerAddress: Address;
|
|
91
|
+
args: GetFeeArgs;
|
|
92
|
+
}): Unwrapable<Call> => {
|
|
93
|
+
return createCall({
|
|
94
|
+
operation: 0,
|
|
95
|
+
to: routerAddress,
|
|
96
|
+
data: CCIPGetFeeCalldata(args),
|
|
97
|
+
value: 0n,
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// ─── ccipSend ────────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
export type CCIPSendArgs = Readonly<{
|
|
104
|
+
destinationChainSelector: string;
|
|
105
|
+
message: EVM2AnyMessage;
|
|
106
|
+
/** Native fee (from getFee). The Router does NOT refund excess. */
|
|
107
|
+
nativeFee: bigint;
|
|
108
|
+
}>;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Encode calldata for Router.ccipSend(destinationChainSelector, message).
|
|
112
|
+
*/
|
|
113
|
+
export const CCIPSendCalldata = (args: CCIPSendArgs): HexString => {
|
|
114
|
+
return ccipRouterInterface.encodeFunctionData("ccipSend", [
|
|
115
|
+
args.destinationChainSelector,
|
|
116
|
+
{
|
|
117
|
+
receiver: args.message.receiver,
|
|
118
|
+
data: args.message.data,
|
|
119
|
+
tokenAmounts: args.message.tokenAmounts.map((t) => ({
|
|
120
|
+
token: t.token,
|
|
121
|
+
amount: t.amount,
|
|
122
|
+
})),
|
|
123
|
+
feeToken: args.message.feeToken,
|
|
124
|
+
extraArgs: args.message.extraArgs,
|
|
125
|
+
},
|
|
126
|
+
]) as HexString;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Build a Call for Router.ccipSend with msg.value = nativeFee.
|
|
131
|
+
*/
|
|
132
|
+
export const ccipSendTrx = ({
|
|
133
|
+
routerAddress,
|
|
134
|
+
args,
|
|
135
|
+
}: {
|
|
136
|
+
routerAddress: Address;
|
|
137
|
+
args: CCIPSendArgs;
|
|
138
|
+
}): Unwrapable<Call> => {
|
|
139
|
+
return createCall({
|
|
140
|
+
operation: 0,
|
|
141
|
+
to: routerAddress,
|
|
142
|
+
data: CCIPSendCalldata(args),
|
|
143
|
+
value: args.nativeFee,
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// ─── Helper: build EVM2AnyMessage for a single token bridge ──────────────
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Build a standard EVM2AnyMessage for bridging a single token.
|
|
151
|
+
* Receiver = abi.encode(destinationAddress), feeToken = address(0) (native).
|
|
152
|
+
*/
|
|
153
|
+
export const buildCCIPMessage = ({
|
|
154
|
+
receiver,
|
|
155
|
+
token,
|
|
156
|
+
amount,
|
|
157
|
+
}: {
|
|
158
|
+
receiver: Address;
|
|
159
|
+
token: Address;
|
|
160
|
+
amount: bigint;
|
|
161
|
+
}): EVM2AnyMessage => {
|
|
162
|
+
// Pad receiver to 32 bytes (abi.encode(address))
|
|
163
|
+
const receiverEncoded = ("0x" + receiver.slice(2).padStart(64, "0")) as HexString;
|
|
164
|
+
|
|
165
|
+
return Object.freeze({
|
|
166
|
+
receiver: receiverEncoded,
|
|
167
|
+
data: "0x" as HexString,
|
|
168
|
+
tokenAmounts: Object.freeze([Object.freeze({ token, amount })]),
|
|
169
|
+
feeToken: "0x0000000000000000000000000000000000000000" as Address,
|
|
170
|
+
extraArgs: "0x" as HexString,
|
|
171
|
+
});
|
|
172
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { default as CCIPRouterAbi } from "./ccip.router.abi";
|
|
2
|
+
export {
|
|
3
|
+
// Chain selectors
|
|
4
|
+
CCIP_CHAIN_SELECTORS,
|
|
5
|
+
getCCIPChainSelector,
|
|
6
|
+
// getFee
|
|
7
|
+
CCIPGetFeeCalldata,
|
|
8
|
+
CCIPGetFeeTrx,
|
|
9
|
+
// ccipSend
|
|
10
|
+
CCIPSendCalldata,
|
|
11
|
+
ccipSendTrx,
|
|
12
|
+
// Helper
|
|
13
|
+
buildCCIPMessage,
|
|
14
|
+
// Types
|
|
15
|
+
type CCIPTokenAmount,
|
|
16
|
+
type EVM2AnyMessage,
|
|
17
|
+
type GetFeeArgs,
|
|
18
|
+
type CCIPSendArgs,
|
|
19
|
+
} from "./ccip.router";
|
|
@@ -13,6 +13,7 @@ export * from "./slipstream";
|
|
|
13
13
|
export * from "./morphoVault";
|
|
14
14
|
export * from "./merkl";
|
|
15
15
|
export * from "./oft";
|
|
16
|
+
export * from "./ccip";
|
|
16
17
|
export * from "./cctp";
|
|
17
18
|
export * from "./erc721";
|
|
18
19
|
export * from "./iporFusion";
|
|
@@ -22,3 +23,4 @@ export * from "./gearbox";
|
|
|
22
23
|
export * from "./fluidLite";
|
|
23
24
|
export * from "./weth";
|
|
24
25
|
export * from "./pendle";
|
|
26
|
+
export * from "./wormhole";
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client for the Axelar GMP status API — used to track the Axelar side of
|
|
3
|
+
* Monad's 2/2 transceiver stack (Wormhole + Axelar).
|
|
4
|
+
*
|
|
5
|
+
* Axelar's relay network is independent of Wormhole's Executor: if the
|
|
6
|
+
* Executor aborts (e.g. gas-quote rejection), Axelar may still deliver on
|
|
7
|
+
* its own. Checking Axelar status helps decide how to recover.
|
|
8
|
+
*
|
|
9
|
+
* API reference: https://docs.axelarscan.io/gmp
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { HexString } from "../../types";
|
|
13
|
+
|
|
14
|
+
export const AXELAR_GMP_API_MAINNET = "https://api.axelarscan.io" as const;
|
|
15
|
+
export const AXELAR_GMP_API_TESTNET = "https://testnet.api.axelarscan.io" as const;
|
|
16
|
+
|
|
17
|
+
export type AxelarNetwork = "Mainnet" | "Testnet";
|
|
18
|
+
|
|
19
|
+
export const getAxelarGmpApiUrl = (network: AxelarNetwork = "Mainnet"): string =>
|
|
20
|
+
network === "Mainnet" ? AXELAR_GMP_API_MAINNET : AXELAR_GMP_API_TESTNET;
|
|
21
|
+
|
|
22
|
+
// ─── POST /gmp/searchGMP ─────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Simplified status returned by Axelar's GMP API.
|
|
26
|
+
* See {@link https://docs.axelarscan.io/gmp} for the full shape — this helper
|
|
27
|
+
* surfaces just the status flags most useful for recovery decisions.
|
|
28
|
+
*/
|
|
29
|
+
export type AxelarGmpStatus = Readonly<{
|
|
30
|
+
/** Raw Axelar status — common values: "called", "confirming", "approved", "executed", "error". */
|
|
31
|
+
status: string;
|
|
32
|
+
/** Higher-level status — "received" when the message landed on the destination. */
|
|
33
|
+
simplifiedStatus?: string;
|
|
34
|
+
/** Did the destination-side execution succeed? */
|
|
35
|
+
executed: boolean;
|
|
36
|
+
/** Was the payload approved by Axelar validators? */
|
|
37
|
+
approved: boolean;
|
|
38
|
+
/** Destination-chain tx hash (if executed). */
|
|
39
|
+
destinationTxHash?: HexString;
|
|
40
|
+
/** Destination-chain block number (if executed). */
|
|
41
|
+
destinationBlockNumber?: number;
|
|
42
|
+
/** Underlying raw object — inspect for fields not surfaced above. */
|
|
43
|
+
raw: unknown;
|
|
44
|
+
}>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Fetch the Axelar GMP status for a source-chain transaction that triggered
|
|
48
|
+
* an Axelar message (e.g. the Monad-side `MultiNTTWithExecutor.transfer`
|
|
49
|
+
* invocation).
|
|
50
|
+
*
|
|
51
|
+
* Returns `null` if Axelar has not yet indexed the transaction.
|
|
52
|
+
*/
|
|
53
|
+
export const fetchAxelarGmpStatus = async (
|
|
54
|
+
{ sourceTxHash }: { sourceTxHash: HexString },
|
|
55
|
+
network: AxelarNetwork = "Mainnet",
|
|
56
|
+
): Promise<AxelarGmpStatus | null> => {
|
|
57
|
+
const response = await fetch(`${getAxelarGmpApiUrl(network)}/gmp/searchGMP`, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: { "Content-Type": "application/json" },
|
|
60
|
+
body: JSON.stringify({ txHash: sourceTxHash }),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
const body = await response.text().catch(() => "");
|
|
65
|
+
throw new Error(`Axelar GMP status API returned ${response.status} ${response.statusText}: ${body}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const parsed = (await response.json()) as {
|
|
69
|
+
data?: Array<Record<string, unknown>>;
|
|
70
|
+
};
|
|
71
|
+
const entry = parsed.data?.[0];
|
|
72
|
+
if (!entry) return null;
|
|
73
|
+
|
|
74
|
+
const executedEntry = entry["executed"] as { transactionHash?: HexString; blockNumber?: number } | undefined;
|
|
75
|
+
|
|
76
|
+
return Object.freeze({
|
|
77
|
+
status: String(entry["status"] ?? "unknown"),
|
|
78
|
+
simplifiedStatus: entry["simplified_status"] as string | undefined,
|
|
79
|
+
executed: Boolean(entry["executed"]),
|
|
80
|
+
approved: Boolean(entry["approved"]),
|
|
81
|
+
destinationTxHash: executedEntry?.transactionHash,
|
|
82
|
+
destinationBlockNumber: executedEntry?.blockNumber,
|
|
83
|
+
raw: entry,
|
|
84
|
+
});
|
|
85
|
+
};
|