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.
Files changed (48) hide show
  1. package/dist/index.cjs +689 -46
  2. package/dist/index.cjs.map +18 -3
  3. package/dist/index.js +47397 -40297
  4. package/dist/index.js.map +134 -72
  5. package/dist/integrations/ccip/ccip.router.abi.d.ts +85 -0
  6. package/dist/integrations/ccip/ccip.router.abi.d.ts.map +1 -0
  7. package/dist/integrations/ccip/ccip.router.d.ts +72 -0
  8. package/dist/integrations/ccip/ccip.router.d.ts.map +1 -0
  9. package/dist/integrations/ccip/index.d.ts +3 -0
  10. package/dist/integrations/ccip/index.d.ts.map +1 -0
  11. package/dist/integrations/index.d.ts +2 -0
  12. package/dist/integrations/index.d.ts.map +1 -1
  13. package/dist/integrations/wormhole/axelar.gmp.api.d.ts +47 -0
  14. package/dist/integrations/wormhole/axelar.gmp.api.d.ts.map +1 -0
  15. package/dist/integrations/wormhole/executor.quote.api.d.ts +100 -0
  16. package/dist/integrations/wormhole/executor.quote.api.d.ts.map +1 -0
  17. package/dist/integrations/wormhole/gmp.manager.abi.d.ts +32 -0
  18. package/dist/integrations/wormhole/gmp.manager.abi.d.ts.map +1 -0
  19. package/dist/integrations/wormhole/gmp.manager.d.ts +65 -0
  20. package/dist/integrations/wormhole/gmp.manager.d.ts.map +1 -0
  21. package/dist/integrations/wormhole/index.d.ts +10 -0
  22. package/dist/integrations/wormhole/index.d.ts.map +1 -0
  23. package/dist/integrations/wormhole/wormhole.multi.ntt.abi.d.ts +101 -0
  24. package/dist/integrations/wormhole/wormhole.multi.ntt.abi.d.ts.map +1 -0
  25. package/dist/integrations/wormhole/wormhole.multi.ntt.d.ts +149 -0
  26. package/dist/integrations/wormhole/wormhole.multi.ntt.d.ts.map +1 -0
  27. package/dist/integrations/wormhole/wormhole.scan.api.d.ts +56 -0
  28. package/dist/integrations/wormhole/wormhole.scan.api.d.ts.map +1 -0
  29. package/dist/integrations/wormhole/wormhole.transceiver.abi.d.ts +23 -0
  30. package/dist/integrations/wormhole/wormhole.transceiver.abi.d.ts.map +1 -0
  31. package/dist/integrations/wormhole/wormhole.transceiver.d.ts +28 -0
  32. package/dist/integrations/wormhole/wormhole.transceiver.d.ts.map +1 -0
  33. package/package.json +3 -2
  34. package/src/integrations/ccip/ccip.router.abi.ts +62 -0
  35. package/src/integrations/ccip/ccip.router.ts +172 -0
  36. package/src/integrations/ccip/index.ts +19 -0
  37. package/src/integrations/index.ts +2 -0
  38. package/src/integrations/wormhole/axelar.gmp.api.ts +85 -0
  39. package/src/integrations/wormhole/executor.quote.api.ts +182 -0
  40. package/src/integrations/wormhole/gmp.manager.abi.ts +26 -0
  41. package/src/integrations/wormhole/gmp.manager.ts +129 -0
  42. package/src/integrations/wormhole/index.ts +68 -0
  43. package/src/integrations/wormhole/wormhole.multi.ntt.abi.ts +68 -0
  44. package/src/integrations/wormhole/wormhole.multi.ntt.ts +259 -0
  45. package/src/integrations/wormhole/wormhole.scan.api.ts +95 -0
  46. package/src/integrations/wormhole/wormhole.transceiver.abi.ts +20 -0
  47. package/src/integrations/wormhole/wormhole.transceiver.ts +46 -0
  48. package/src/lib/contractsRegistry.json +6 -2
@@ -0,0 +1,259 @@
1
+ import { ethers } from "ethers";
2
+ import { concatHex, pad, toHex } from "viem";
3
+ import wormholeMultiNttAbi from "./wormhole.multi.ntt.abi";
4
+ import type { Address } from "viem";
5
+ import type { Call, HexString, Unwrapable } from "../../types";
6
+ import { createCall } from "../../types";
7
+
8
+ const wormholeMultiNttInterface = new ethers.utils.Interface(wormholeMultiNttAbi as any);
9
+
10
+ /**
11
+ * Wormhole uint16 chain IDs.
12
+ *
13
+ * Wormhole uses its own chain-ID space distinct from EVM chain IDs.
14
+ * Reference: https://wormhole.com/docs/products/reference/chain-ids/
15
+ */
16
+ export const WORMHOLE_CHAIN_IDS: Readonly<Record<number, number>> = Object.freeze({
17
+ 1: 2, // Ethereum Mainnet
18
+ 143: 48, // Monad
19
+ });
20
+
21
+ /**
22
+ * Resolve the Wormhole chain ID for an EVM chain ID.
23
+ * @throws if the chain has no Wormhole chain ID registered.
24
+ */
25
+ export const getWormholeChainId = (chainId: number): number => {
26
+ const whChainId = WORMHOLE_CHAIN_IDS[chainId];
27
+ if (whChainId === undefined) {
28
+ throw new Error(`Wormhole: No chain ID mapping for chainId ${chainId}`);
29
+ }
30
+ return whChainId;
31
+ };
32
+
33
+ /**
34
+ * Left-pad a 20-byte address to bytes32 (the standard ABI encoding used
35
+ * by Wormhole NTT for `recipient` / `refundAddress` fields).
36
+ */
37
+ export const addressToBytes32 = (addr: Address): HexString => pad(addr, { size: 32 }).toLowerCase() as HexString;
38
+
39
+ // ─── Structs ─────────────────────────────────────────────────────────────
40
+
41
+ export type ExecutorArgs = Readonly<{
42
+ /** Relay fee paid to the executor (forwarded as msg.value). */
43
+ value: bigint;
44
+ /** Where the executor refunds unused gas on the SOURCE chain. */
45
+ refundAddress: Address;
46
+ /** Signed quote bytes from the executor API. */
47
+ signedQuote: HexString;
48
+ /** Relay instructions bytes (see buildRelayInstructions). */
49
+ instructions: HexString;
50
+ }>;
51
+
52
+ export type FeeArgs = Readonly<{
53
+ /** App-level fee in deci-basis points (10_000 = 100%). Always 0 for DAMM. */
54
+ dbps: number;
55
+ /** Fee recipient. Irrelevant when dbps = 0. */
56
+ payee: Address;
57
+ }>;
58
+
59
+ // ─── transfer() ──────────────────────────────────────────────────────────
60
+
61
+ export type WormholeTransferArgs = Readonly<{
62
+ /** MultiTokenNTT manager address on the source chain. */
63
+ multiTokenNtt: Address;
64
+ /** ERC20 token to bridge (e.g. WETH). */
65
+ token: Address;
66
+ /** Amount to bridge (token smallest unit). */
67
+ amount: bigint;
68
+ /** Destination chain (Wormhole chain ID, not EVM). */
69
+ recipientChain: number;
70
+ /** Destination address (bytes32, left-padded). Use addressToBytes32(). */
71
+ recipient: HexString;
72
+ /** Top-level refund address on the DESTINATION chain (bytes32). */
73
+ refundAddress: HexString;
74
+ /** Transceiver instructions. Pass "0x" for defaults. */
75
+ transceiverInstructions: HexString;
76
+ executorArgs: ExecutorArgs;
77
+ feeArgs: FeeArgs;
78
+ }>;
79
+
80
+ /**
81
+ * Encode calldata for `MultiNTTWithExecutor.transfer(...)`.
82
+ */
83
+ export const WormholeTransferCalldata = (args: WormholeTransferArgs): HexString => {
84
+ return wormholeMultiNttInterface.encodeFunctionData("transfer", [
85
+ args.multiTokenNtt,
86
+ args.token,
87
+ args.amount,
88
+ args.recipientChain,
89
+ args.recipient,
90
+ args.refundAddress,
91
+ args.transceiverInstructions,
92
+ {
93
+ value: args.executorArgs.value,
94
+ refundAddress: args.executorArgs.refundAddress,
95
+ signedQuote: args.executorArgs.signedQuote,
96
+ instructions: args.executorArgs.instructions,
97
+ },
98
+ {
99
+ dbps: args.feeArgs.dbps,
100
+ payee: args.feeArgs.payee,
101
+ },
102
+ ]) as HexString;
103
+ };
104
+
105
+ /**
106
+ * Build a Call for `MultiNTTWithExecutor.transfer(...)`.
107
+ *
108
+ * `msg.value` = `executorArgs.value` (Executor relay fee) + any per-transceiver
109
+ * delivery fees required by the underlying `MultiTokenNTT` (e.g. Axelar's
110
+ * gateway fee on the Monad ↔ Ethereum lane).
111
+ *
112
+ * Pass `transceiverFee` when the `MultiTokenNTT` uses a paid transceiver in
113
+ * addition to Wormhole's guardian signing. Query the exact amount via
114
+ * `GmpManager.quoteDeliveryPrice(recipientChain, transceiverInstructions)`
115
+ * (see `GmpManagerQuoteDeliveryPriceCalldata`).
116
+ */
117
+ export const wormholeTransferTrx = ({
118
+ wrapperAddress,
119
+ args,
120
+ transceiverFee = 0n,
121
+ }: {
122
+ /** MultiNTTWithExecutor address on the source chain. */
123
+ wrapperAddress: Address;
124
+ args: WormholeTransferArgs;
125
+ /** Extra native token required by paid transceivers (e.g. Axelar). */
126
+ transceiverFee?: bigint;
127
+ }): Unwrapable<Call> => {
128
+ return createCall({
129
+ operation: 0,
130
+ to: wrapperAddress,
131
+ data: WormholeTransferCalldata(args),
132
+ value: args.executorArgs.value + transceiverFee,
133
+ });
134
+ };
135
+
136
+ // ─── Relay Instructions ──────────────────────────────────────────────────
137
+
138
+ /**
139
+ * Default `gasLimit` for `MultiTokenNTT` redemption on the destination chain.
140
+ *
141
+ * MultiNTT redemption is expensive because it:
142
+ * (a) verifies the Wormhole VAA (guardian signatures + replay protection)
143
+ * (b) verifies the sibling transceiver's attestation (2/2 check)
144
+ * (c) executes the token mint/transfer on the destination `MultiTokenNTT`
145
+ *
146
+ * Empirically, successful Monad ↔ Mainnet transfers use ~650_000 gas; manual
147
+ * `receiveMessage` calls land in ~330_000. Default is 1_000_000 to leave
148
+ * headroom for future protocol upgrades and any per-block variance — the
149
+ * extra cost is tiny (~$0.20 per Monad→Mainnet bridge at typical prices)
150
+ * and eliminates `evm_simulation_gas_too_low` rejections from the Executor.
151
+ *
152
+ * Note: this is gas UNITS, not gas PRICE. It does not need to track network
153
+ * congestion — destination-chain gas usage is deterministic. What network
154
+ * spikes affect is the COST of providing this budget; that's bounded
155
+ * separately by the `etherWithinAllowance` permission cap in the kit.
156
+ *
157
+ * Override per-call via `buildRelayInstructions({ gasLimit: N })` if you have
158
+ * empirical data showing a different value is appropriate for your asset/lane.
159
+ */
160
+ export const DEFAULT_NTT_REDEMPTION_GAS_LIMIT = 1_000_000n;
161
+
162
+ /**
163
+ * Encode `GasInstruction` relay instructions for the executor.
164
+ *
165
+ * Format (per Wormhole SDK): `0x01` (version) || uint128 gasLimit || uint128 msgValue
166
+ * - `gasLimit`: gas units the executor should provide when redeeming on the destination
167
+ * - `msgValue`: native token (in wei on destination) to forward with the redemption call
168
+ *
169
+ * Default `gasLimit` is `DEFAULT_NTT_REDEMPTION_GAS_LIMIT` (650k), calibrated
170
+ * for `MultiTokenNTT` with a 2/2 transceiver stack. Override only if you know
171
+ * the destination chain's redemption consumes less.
172
+ */
173
+ export const buildRelayInstructions = ({
174
+ gasLimit = DEFAULT_NTT_REDEMPTION_GAS_LIMIT,
175
+ msgValue = 0n,
176
+ }: {
177
+ gasLimit?: bigint;
178
+ msgValue?: bigint;
179
+ } = {}): HexString => {
180
+ if (gasLimit < 0n) throw new Error("buildRelayInstructions: negative gasLimit");
181
+ if (msgValue < 0n) throw new Error("buildRelayInstructions: negative msgValue");
182
+ return concatHex([
183
+ "0x01", // version
184
+ toHex(gasLimit, { size: 16 }),
185
+ toHex(msgValue, { size: 16 }),
186
+ ]) as HexString;
187
+ };
188
+
189
+ // ─── calculateFee() ──────────────────────────────────────────────────────
190
+
191
+ /**
192
+ * Encode calldata for the view function `calculateFee(amount, dbps)`.
193
+ * Useful to query the dbps-based fee charged by the wrapper off-chain.
194
+ */
195
+ export const WormholeCalculateFeeCalldata = ({ amount, dbps }: { amount: bigint; dbps: number }): HexString => {
196
+ return wormholeMultiNttInterface.encodeFunctionData("calculateFee", [amount, dbps]) as HexString;
197
+ };
198
+
199
+ // ─── Helper: assemble a full transfer args object ────────────────────────
200
+
201
+ /**
202
+ * Compose a `WormholeTransferArgs` where recipient and refund addresses
203
+ * default to the same avatar (the Safe on both chains share an address).
204
+ *
205
+ * This matches the permission constraint in Our-DeFi-Kit's
206
+ * `WormholeBridgingPermissions`, which scopes `recipient`, top-level
207
+ * `refundAddress`, and `executorArgs.refundAddress` all to `c.avatar`.
208
+ */
209
+ export const buildWormholeTransferArgsFromAvatar = ({
210
+ multiTokenNtt,
211
+ token,
212
+ amount,
213
+ recipientChain,
214
+ avatar,
215
+ relayFee,
216
+ signedQuote,
217
+ relayInstructions,
218
+ transceiverInstructions = "0x" as HexString,
219
+ dbps = 0,
220
+ payee,
221
+ }: {
222
+ multiTokenNtt: Address;
223
+ token: Address;
224
+ amount: bigint;
225
+ /** Wormhole chain ID (not EVM). */
226
+ recipientChain: number;
227
+ /** The Safe address (same on source + destination). */
228
+ avatar: Address;
229
+ /** Native relay fee to forward (from signed quote estimatedCost). */
230
+ relayFee: bigint;
231
+ signedQuote: HexString;
232
+ relayInstructions: HexString;
233
+ transceiverInstructions?: HexString;
234
+ /** Defaults to 0 — DAMM never charges a skim fee. */
235
+ dbps?: number;
236
+ /** Defaults to the zero address when dbps = 0 (irrelevant). */
237
+ payee?: Address;
238
+ }): WormholeTransferArgs => {
239
+ const avatarBytes32 = addressToBytes32(avatar);
240
+ return Object.freeze({
241
+ multiTokenNtt,
242
+ token,
243
+ amount,
244
+ recipientChain,
245
+ recipient: avatarBytes32,
246
+ refundAddress: avatarBytes32,
247
+ transceiverInstructions,
248
+ executorArgs: Object.freeze({
249
+ value: relayFee,
250
+ refundAddress: avatar,
251
+ signedQuote,
252
+ instructions: relayInstructions,
253
+ }),
254
+ feeArgs: Object.freeze({
255
+ dbps,
256
+ payee: payee ?? ("0x0000000000000000000000000000000000000000" as Address),
257
+ }),
258
+ });
259
+ };
@@ -0,0 +1,95 @@
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
+
12
+ import { bytesToHex, pad, size as hexSize } from "viem";
13
+ import type { HexString } from "../../types";
14
+
15
+ export const WORMHOLESCAN_API_MAINNET = "https://api.wormholescan.io" as const;
16
+ export const WORMHOLESCAN_API_TESTNET = "https://api.testnet.wormholescan.io" as const;
17
+
18
+ export type WormholeNetworkEnv = "Mainnet" | "Testnet";
19
+
20
+ export const getWormholeScanApiUrl = (network: WormholeNetworkEnv = "Mainnet"): string =>
21
+ network === "Mainnet" ? WORMHOLESCAN_API_MAINNET : WORMHOLESCAN_API_TESTNET;
22
+
23
+ // ─── VAA lookup by (chain, emitter, sequence) ────────────────────────────
24
+
25
+ /**
26
+ * Convert a 20-byte address to the 64-char (32-byte) padded lowercase hex
27
+ * format WormholeScan expects for the `emitter` URL segment.
28
+ */
29
+ export const normalizeEmitterForVaaLookup = (emitter: HexString): string => {
30
+ const byteLen = hexSize(emitter);
31
+ if (byteLen !== 20 && byteLen !== 32) {
32
+ throw new Error(`normalizeEmitterForVaaLookup: expected 20- or 32-byte hex, got ${byteLen} bytes`);
33
+ }
34
+ // 0x-prefixed, left-padded to 32 bytes, lowercase, no 0x in return value
35
+ return pad(emitter, { size: 32 }).slice(2).toLowerCase();
36
+ };
37
+
38
+ export type VaaLookupArgs = Readonly<{
39
+ /** Wormhole chain ID of the source chain (NOT EVM chainId). */
40
+ emitterChain: number;
41
+ /** Source-chain transceiver address — 20 or 32 byte hex. */
42
+ emitterAddress: HexString;
43
+ /** Sequence number emitted by the Wormhole core bridge. */
44
+ sequence: number | bigint;
45
+ }>;
46
+
47
+ export type VaaLookupResponse = Readonly<{
48
+ sequence: number;
49
+ id: string;
50
+ emitterChain: number;
51
+ emitterAddr: string;
52
+ emitterNativeAddr: string;
53
+ /** Base64-encoded signed VAA bytes. */
54
+ vaa: string;
55
+ timestamp?: string;
56
+ txHash?: string;
57
+ digest?: string;
58
+ }>;
59
+
60
+ /**
61
+ * Fetch the signed VAA for a given (chain, emitter, sequence).
62
+ *
63
+ * Throws if WormholeScan returns any non-2xx response (including 404, which
64
+ * happens during the brief window after the source tx confirms but before
65
+ * guardians have signed). Callers that want to poll should wrap this in a
66
+ * retry loop — letting the caller decide whether a 404 is a transient
67
+ * "not-yet-signed" or a permanent "wrong inputs" condition.
68
+ */
69
+ export const fetchWormholeVAA = async (
70
+ args: VaaLookupArgs,
71
+ network: WormholeNetworkEnv = "Mainnet",
72
+ ): Promise<VaaLookupResponse> => {
73
+ const emitterPadded = normalizeEmitterForVaaLookup(args.emitterAddress);
74
+ const url = `${getWormholeScanApiUrl(network)}/api/v1/vaas/${args.emitterChain}/${emitterPadded}/${args.sequence.toString()}`;
75
+
76
+ const response = await fetch(url);
77
+ if (!response.ok) {
78
+ const body = await response.text().catch(() => "");
79
+ throw new Error(`WormholeScan VAA lookup returned ${response.status} ${response.statusText}: ${body}`);
80
+ }
81
+ const parsed = (await response.json()) as { data?: VaaLookupResponse };
82
+ if (!parsed.data) {
83
+ throw new Error(
84
+ `WormholeScan VAA lookup returned 200 but no data for chain=${args.emitterChain} emitter=${args.emitterAddress} sequence=${args.sequence}`,
85
+ );
86
+ }
87
+ return parsed.data;
88
+ };
89
+
90
+ /**
91
+ * Decode a base64 VAA string into 0x-prefixed hex bytes, ready for
92
+ * `WormholeReceiveMessageCalldata`.
93
+ */
94
+ export const decodeVaaBase64 = (base64: string): HexString =>
95
+ bytesToHex(Uint8Array.from(atob(base64), (c) => c.charCodeAt(0))) as HexString;
@@ -0,0 +1,20 @@
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
+ export default [
13
+ {
14
+ inputs: [{ name: "encodedMessage", type: "bytes" }],
15
+ name: "receiveMessage",
16
+ outputs: [],
17
+ stateMutability: "nonpayable",
18
+ type: "function",
19
+ },
20
+ ] as const;
@@ -0,0 +1,46 @@
1
+ import { ethers } from "ethers";
2
+ import wormholeTransceiverAbi from "./wormhole.transceiver.abi";
3
+ import type { Address } from "viem";
4
+ import type { Call, HexString, Unwrapable } from "../../types";
5
+ import { createCall } from "../../types";
6
+
7
+ const transceiverInterface = new ethers.utils.Interface(wormholeTransceiverAbi as any);
8
+
9
+ // ─── receiveMessage(bytes encodedMessage) ────────────────────────────────
10
+
11
+ /**
12
+ * Encode calldata for `GenericWormholeTransceiver.receiveMessage(bytes vaa)`.
13
+ *
14
+ * Use this to manually deliver a Wormhole VAA to the destination transceiver
15
+ * when auto-relay has failed (e.g. Executor pre-flight sim rejected the gas
16
+ * quote and aborted). The transceiver verifies the VAA's guardian signatures
17
+ * and forwards the attestation to the `GmpManager`; once the 2/2 threshold is
18
+ * met with the sibling transceiver (e.g. Axelar), `executeMsg` fires
19
+ * automatically in the same transaction.
20
+ */
21
+ export const WormholeReceiveMessageCalldata = ({ vaa }: { vaa: HexString }): HexString => {
22
+ return transceiverInterface.encodeFunctionData("receiveMessage", [vaa]) as HexString;
23
+ };
24
+
25
+ /**
26
+ * Build a Call for manually delivering a VAA to the Wormhole transceiver.
27
+ *
28
+ * The call is permissionless (any EOA works), takes no value, and is safe to
29
+ * retry — the transceiver rejects duplicates.
30
+ */
31
+ export const wormholeReceiveMessageTrx = ({
32
+ transceiverAddress,
33
+ vaa,
34
+ }: {
35
+ /** `GenericWormholeTransceiver` address on the destination chain. */
36
+ transceiverAddress: Address;
37
+ /** The signed VAA bytes, as fetched from WormholeScan. */
38
+ vaa: HexString;
39
+ }): Unwrapable<Call> => {
40
+ return createCall({
41
+ operation: 0,
42
+ to: transceiverAddress,
43
+ data: WormholeReceiveMessageCalldata({ vaa }),
44
+ value: 0n,
45
+ });
46
+ };
@@ -552,7 +552,9 @@
552
552
  "wormhole": {
553
553
  "executor": "0x84EEe8dBa37C36947397E1E11251cA9A06Fc6F8a",
554
554
  "multiTokenNTT": "0x556790e948b9920A8868bCAFcC87D25e82e8a075",
555
- "multiNTTWithExecutor": "0x03dB430D830601DB368991eE55DAa9A708df7912"
555
+ "multiNTTWithExecutor": "0x03dB430D830601DB368991eE55DAa9A708df7912",
556
+ "gmpManager": "0xc6793a32761a11e96c97A3D18fC6545ea931F0E9",
557
+ "genericWormholeTransceiver": "0x9D0eADF3fc10380C4D2F5ba79499C6194549C7D2"
556
558
  },
557
559
  "1inch": {
558
560
  "aggregatorV6": "0x111111125421cA6dc452d289314280a0f8842A65"
@@ -946,7 +948,9 @@
946
948
  "wormhole": {
947
949
  "executor": "0xC04dE634982cAdF2A677310b73630B7Ac56A3f65",
948
950
  "multiTokenNTT": "0x36878C6FCa7e0E8a88F90dc410CfBBcA5B695C95",
949
- "multiNTTWithExecutor": "0xFEA937F7124E19124671f1685671d3f04a9Af4E4"
951
+ "multiNTTWithExecutor": "0xFEA937F7124E19124671f1685671d3f04a9Af4E4",
952
+ "gmpManager": "0x92957b3D0CaB3eA7110fEd1ccc4eF564981a59Fc",
953
+ "genericWormholeTransceiver": "0x1a0f31492Ca69DF6A82906Ce88613AeCD9245C44"
950
954
  },
951
955
  "enso": {
952
956
  "routerV2": "0xCfBAa9Cfce952Ca4F4069874fF1Df8c05e37a3c7"