@m0-foundation/ntt-sdk-route 0.0.13 → 0.0.15
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.d.mts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +274 -58
- package/dist/index.mjs +274 -60
- package/package.json +16 -15
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Network, routes, Chain, ChainContext, TokenId, Signer, ChainAddress, AccountAddress } from '@wormhole-foundation/sdk-connect';
|
|
2
|
-
import { Ntt } from '@wormhole-foundation/sdk-definitions-ntt';
|
|
2
|
+
import { Ntt, NttWithExecutor } from '@wormhole-foundation/sdk-definitions-ntt';
|
|
3
3
|
import { EvmNtt } from '@wormhole-foundation/sdk-evm-ntt';
|
|
4
4
|
import { SolanaNtt } from '@wormhole-foundation/sdk-solana-ntt';
|
|
5
5
|
import { EvmChains, EvmUnsignedTransaction } from '@wormhole-foundation/sdk-evm';
|
|
@@ -21,6 +21,7 @@ type Contracts = Ntt.Contracts & {
|
|
|
21
21
|
declare class M0AutomaticRoute<N extends Network> extends routes.AutomaticRoute<N, Op, Vp, R> implements routes.StaticRouteMethods<typeof M0AutomaticRoute> {
|
|
22
22
|
static NATIVE_GAS_DROPOFF_SUPPORTED: boolean;
|
|
23
23
|
static EVM_WRAPPED_M_TOKEN: string;
|
|
24
|
+
static EXECUTOR_ENTRYPOINT: string;
|
|
24
25
|
static EVM_CONTRACTS: Contracts;
|
|
25
26
|
static meta: {
|
|
26
27
|
name: string;
|
|
@@ -46,6 +47,8 @@ declare class M0AutomaticRoute<N extends Network> extends routes.AutomaticRoute<
|
|
|
46
47
|
createUnsignedTx<N extends Network, C extends EvmChains>(ntt: EvmNtt<N, C>, txReq: TransactionRequest, description: string, parallelizable?: boolean): EvmUnsignedTransaction<N, C>;
|
|
47
48
|
transferSolanaExtension<N extends Network, C extends SolanaChains>(ntt: SolanaNtt<N, C>, sender: AccountAddress<C>, amount: bigint, recipient: ChainAddress, sourceToken: string, destinationToken: string, options: Ntt.TransferOptions, outboxItem?: Keypair): AsyncGenerator<SolanaUnsignedTransaction<N, C>>;
|
|
48
49
|
track(receipt: R, timeout?: number): AsyncGenerator<R, void, unknown>;
|
|
50
|
+
private getExecutorQuote;
|
|
51
|
+
private requiresExecutor;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
type SvmNetwork = Exclude<Network, "Devnet">;
|
|
@@ -61,10 +64,14 @@ declare class SolanaRoutes<N extends Network, C extends SolanaChains> {
|
|
|
61
64
|
constructor(ntt: SolanaNtt<N, C>);
|
|
62
65
|
private static getPrograms;
|
|
63
66
|
private static getExtPrograms;
|
|
64
|
-
static getSolanaContracts(
|
|
67
|
+
static getSolanaContracts(network: Network, chain: SolanaChains): Ntt.Contracts & {
|
|
68
|
+
mLikeTokens: string[];
|
|
69
|
+
};
|
|
70
|
+
getSolanaContracts(): Ntt.Contracts & {
|
|
65
71
|
mLikeTokens: string[];
|
|
66
72
|
};
|
|
67
73
|
getTransferExtensionBurnIx(amount: bigint, recipient: ChainAddress, payer: PublicKey, outboxItem: PublicKey, extMint: PublicKey, destinationToken: Uint8Array, shouldQueue?: boolean): TransactionInstruction;
|
|
74
|
+
getExecutorRelayIx(sender: PublicKey, quote: NttWithExecutor.Quote, destinationChain: Chain): Promise<TransactionInstruction>;
|
|
68
75
|
getReleaseInboundMintExtensionIx(nttMessage: Ntt.Message, emitterChain: Chain, payer: PublicKey, extMint: PublicKey, extAta: PublicKey): TransactionInstruction;
|
|
69
76
|
getAddressLookupTableAccounts(connection: Connection): Promise<AddressLookupTableAccount>;
|
|
70
77
|
static createReleaseInboundMintInstruction<N extends Network, C extends SolanaChains>(ntt: SolanaNtt<N, C>, args: {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Network, routes, Chain, ChainContext, TokenId, Signer, ChainAddress, AccountAddress } from '@wormhole-foundation/sdk-connect';
|
|
2
|
-
import { Ntt } from '@wormhole-foundation/sdk-definitions-ntt';
|
|
2
|
+
import { Ntt, NttWithExecutor } from '@wormhole-foundation/sdk-definitions-ntt';
|
|
3
3
|
import { EvmNtt } from '@wormhole-foundation/sdk-evm-ntt';
|
|
4
4
|
import { SolanaNtt } from '@wormhole-foundation/sdk-solana-ntt';
|
|
5
5
|
import { EvmChains, EvmUnsignedTransaction } from '@wormhole-foundation/sdk-evm';
|
|
@@ -21,6 +21,7 @@ type Contracts = Ntt.Contracts & {
|
|
|
21
21
|
declare class M0AutomaticRoute<N extends Network> extends routes.AutomaticRoute<N, Op, Vp, R> implements routes.StaticRouteMethods<typeof M0AutomaticRoute> {
|
|
22
22
|
static NATIVE_GAS_DROPOFF_SUPPORTED: boolean;
|
|
23
23
|
static EVM_WRAPPED_M_TOKEN: string;
|
|
24
|
+
static EXECUTOR_ENTRYPOINT: string;
|
|
24
25
|
static EVM_CONTRACTS: Contracts;
|
|
25
26
|
static meta: {
|
|
26
27
|
name: string;
|
|
@@ -46,6 +47,8 @@ declare class M0AutomaticRoute<N extends Network> extends routes.AutomaticRoute<
|
|
|
46
47
|
createUnsignedTx<N extends Network, C extends EvmChains>(ntt: EvmNtt<N, C>, txReq: TransactionRequest, description: string, parallelizable?: boolean): EvmUnsignedTransaction<N, C>;
|
|
47
48
|
transferSolanaExtension<N extends Network, C extends SolanaChains>(ntt: SolanaNtt<N, C>, sender: AccountAddress<C>, amount: bigint, recipient: ChainAddress, sourceToken: string, destinationToken: string, options: Ntt.TransferOptions, outboxItem?: Keypair): AsyncGenerator<SolanaUnsignedTransaction<N, C>>;
|
|
48
49
|
track(receipt: R, timeout?: number): AsyncGenerator<R, void, unknown>;
|
|
50
|
+
private getExecutorQuote;
|
|
51
|
+
private requiresExecutor;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
type SvmNetwork = Exclude<Network, "Devnet">;
|
|
@@ -61,10 +64,14 @@ declare class SolanaRoutes<N extends Network, C extends SolanaChains> {
|
|
|
61
64
|
constructor(ntt: SolanaNtt<N, C>);
|
|
62
65
|
private static getPrograms;
|
|
63
66
|
private static getExtPrograms;
|
|
64
|
-
static getSolanaContracts(
|
|
67
|
+
static getSolanaContracts(network: Network, chain: SolanaChains): Ntt.Contracts & {
|
|
68
|
+
mLikeTokens: string[];
|
|
69
|
+
};
|
|
70
|
+
getSolanaContracts(): Ntt.Contracts & {
|
|
65
71
|
mLikeTokens: string[];
|
|
66
72
|
};
|
|
67
73
|
getTransferExtensionBurnIx(amount: bigint, recipient: ChainAddress, payer: PublicKey, outboxItem: PublicKey, extMint: PublicKey, destinationToken: Uint8Array, shouldQueue?: boolean): TransactionInstruction;
|
|
74
|
+
getExecutorRelayIx(sender: PublicKey, quote: NttWithExecutor.Quote, destinationChain: Chain): Promise<TransactionInstruction>;
|
|
68
75
|
getReleaseInboundMintExtensionIx(nttMessage: Ntt.Message, emitterChain: Chain, payer: PublicKey, extMint: PublicKey, extAta: PublicKey): TransactionInstruction;
|
|
69
76
|
getAddressLookupTableAccounts(connection: Connection): Promise<AddressLookupTableAccount>;
|
|
70
77
|
static createReleaseInboundMintInstruction<N extends Network, C extends SolanaChains>(ntt: SolanaNtt<N, C>, args: {
|
package/dist/index.js
CHANGED
|
@@ -2,19 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
var sdkConnect = require('@wormhole-foundation/sdk-connect');
|
|
4
4
|
var sdkDefinitionsNtt = require('@wormhole-foundation/sdk-definitions-ntt');
|
|
5
|
-
var sdkSolanaNtt = require('@wormhole-foundation/sdk-solana-ntt');
|
|
6
5
|
var sdkEvm = require('@wormhole-foundation/sdk-evm');
|
|
7
6
|
var sdkSolana = require('@wormhole-foundation/sdk-solana');
|
|
8
7
|
var sdkRouteNtt = require('@wormhole-foundation/sdk-route-ntt');
|
|
9
8
|
var ethers = require('ethers');
|
|
10
9
|
var web3_js = require('@solana/web3.js');
|
|
11
10
|
var splToken = require('@solana/spl-token');
|
|
11
|
+
var sdkSolanaNtt = require('@wormhole-foundation/sdk-solana-ntt');
|
|
12
12
|
var BN = require('bn.js');
|
|
13
13
|
var sha2 = require('@noble/hashes/sha2');
|
|
14
|
+
var evm = require('@wormhole-foundation/sdk/platforms/evm');
|
|
15
|
+
var solana = require('@wormhole-foundation/sdk/platforms/solana');
|
|
14
16
|
|
|
15
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
18
|
|
|
17
19
|
var BN__default = /*#__PURE__*/_interopDefault(BN);
|
|
20
|
+
var evm__default = /*#__PURE__*/_interopDefault(evm);
|
|
21
|
+
var solana__default = /*#__PURE__*/_interopDefault(solana);
|
|
18
22
|
|
|
19
23
|
// src/m0AutomaticRoute.ts
|
|
20
24
|
var SolanaRoutes = class _SolanaRoutes {
|
|
@@ -22,7 +26,10 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
22
26
|
this.ntt = ntt;
|
|
23
27
|
this.network = ntt.network;
|
|
24
28
|
this.programs = _SolanaRoutes.getPrograms(this.network);
|
|
25
|
-
this.extPrograms = _SolanaRoutes.getExtPrograms(
|
|
29
|
+
this.extPrograms = _SolanaRoutes.getExtPrograms(
|
|
30
|
+
this.network,
|
|
31
|
+
this.ntt.chain
|
|
32
|
+
);
|
|
26
33
|
}
|
|
27
34
|
static getPrograms(network) {
|
|
28
35
|
return {
|
|
@@ -30,7 +37,7 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
30
37
|
swap: pk("MSwapi3WhNKMUGm9YrxGhypgUEt7wYQH3ZgG32XoWzH"),
|
|
31
38
|
earn: pk("mz2vDzjbQDUDXBH6FPF5s4odCJ4y8YLE5QWaZ8XdZ9Z"),
|
|
32
39
|
lut: pk("9JLRqBqkznKiSoNfotA4ywSRdnWb2fE76SiFrAfkaRCD"),
|
|
33
|
-
mMint: pk("
|
|
40
|
+
mMint: pk("mzerojk9tg56ebsrEAhfkyc9VgKjTW2zDqp6C5mhjzH"),
|
|
34
41
|
portal: pk("mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY"),
|
|
35
42
|
quoter: pk("Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ")
|
|
36
43
|
},
|
|
@@ -38,13 +45,21 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
38
45
|
swap: pk("MSwapi3WhNKMUGm9YrxGhypgUEt7wYQH3ZgG32XoWzH"),
|
|
39
46
|
earn: pk("mz2vDzjbQDUDXBH6FPF5s4odCJ4y8YLE5QWaZ8XdZ9Z"),
|
|
40
47
|
lut: pk("6GhuWPuAmiJeeSVsr58KjqHcAejJRndCx9BVtHkaYHUR"),
|
|
41
|
-
mMint: pk("
|
|
48
|
+
mMint: pk("mzerojk9tg56ebsrEAhfkyc9VgKjTW2zDqp6C5mhjzH"),
|
|
42
49
|
portal: pk("mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY"),
|
|
43
50
|
quoter: pk("Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ")
|
|
44
51
|
}
|
|
45
52
|
}[network];
|
|
46
53
|
}
|
|
47
|
-
static getExtPrograms(network) {
|
|
54
|
+
static getExtPrograms(network, chain) {
|
|
55
|
+
if (chain === "Fogo") {
|
|
56
|
+
return {
|
|
57
|
+
fUSDqquEMUU8UmU2YWYGZy2Lda1oMzBc88Mkzc1PRDw: {
|
|
58
|
+
program: pk("extUkDFf3HLekkxbcZ3XRUizMjbxMJgKBay3p9xGVmg"),
|
|
59
|
+
tokenProgram: splToken.TOKEN_PROGRAM_ID
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
48
63
|
return {
|
|
49
64
|
Mainnet: {
|
|
50
65
|
mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp: {
|
|
@@ -72,16 +87,19 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
72
87
|
usdkyPPxgV7sfNyKb8eDz66ogPrkRXG3wS2FVb6LLUf: {
|
|
73
88
|
program: pk("3PskKTHgboCbUSQPMcCAZdZNFHbNvSoZ8zEFYANCdob7"),
|
|
74
89
|
tokenProgram: splToken.TOKEN_2022_PROGRAM_ID
|
|
90
|
+
},
|
|
91
|
+
fUSDqquEMUU8UmU2YWYGZy2Lda1oMzBc88Mkzc1PRDw: {
|
|
92
|
+
program: pk("extUkDFf3HLekkxbcZ3XRUizMjbxMJgKBay3p9xGVmg"),
|
|
93
|
+
tokenProgram: splToken.TOKEN_PROGRAM_ID
|
|
75
94
|
}
|
|
76
95
|
}
|
|
77
96
|
}[network];
|
|
78
97
|
}
|
|
79
|
-
static getSolanaContracts(
|
|
80
|
-
const programs = _SolanaRoutes.getPrograms(
|
|
81
|
-
chainContext.network
|
|
82
|
-
);
|
|
98
|
+
static getSolanaContracts(network, chain) {
|
|
99
|
+
const programs = _SolanaRoutes.getPrograms(network);
|
|
83
100
|
const extPrograms = _SolanaRoutes.getExtPrograms(
|
|
84
|
-
|
|
101
|
+
network,
|
|
102
|
+
chain
|
|
85
103
|
);
|
|
86
104
|
return {
|
|
87
105
|
token: programs.mMint.toBase58(),
|
|
@@ -91,10 +109,19 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
91
109
|
quoter: programs.quoter.toBase58()
|
|
92
110
|
};
|
|
93
111
|
}
|
|
112
|
+
getSolanaContracts() {
|
|
113
|
+
return _SolanaRoutes.getSolanaContracts(this.network, this.ntt.chain);
|
|
114
|
+
}
|
|
94
115
|
getTransferExtensionBurnIx(amount2, recipient, payer, outboxItem, extMint, destinationToken, shouldQueue = true) {
|
|
95
|
-
const recipientAddress =
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
const recipientAddress = sdkConnect.toUniversal(
|
|
117
|
+
recipient.chain,
|
|
118
|
+
recipient.address.toString()
|
|
119
|
+
).toUint8Array();
|
|
120
|
+
if (recipientAddress.length !== 32) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
`recipient address must be 32 bytes, got ${recipientAddress.length} bytes`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
98
125
|
if (destinationToken.length !== 32) {
|
|
99
126
|
throw new Error(
|
|
100
127
|
`destinationToken must be 32 bytes, got ${destinationToken.length} bytes`
|
|
@@ -107,6 +134,16 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
107
134
|
);
|
|
108
135
|
}
|
|
109
136
|
const { program: extProgram, tokenProgram: extTokenProgram } = extension;
|
|
137
|
+
const [tokenAuth] = web3_js.PublicKey.findProgramAddressSync(
|
|
138
|
+
[Buffer.from("token_authority")],
|
|
139
|
+
this.programs.portal
|
|
140
|
+
);
|
|
141
|
+
const sessionAuth = this.ntt.pdas.sessionAuthority(tokenAuth, {
|
|
142
|
+
amount: new BN__default.default(amount2),
|
|
143
|
+
recipientChain: { id: sdkConnect.chainToChainId(recipient.chain) },
|
|
144
|
+
recipientAddress: [...recipientAddress],
|
|
145
|
+
shouldQueue
|
|
146
|
+
});
|
|
110
147
|
return new web3_js.TransactionInstruction({
|
|
111
148
|
programId: this.ntt.program.programId,
|
|
112
149
|
keys: [
|
|
@@ -131,10 +168,7 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
131
168
|
// from (token auth m token account)
|
|
132
169
|
pubkey: splToken.getAssociatedTokenAddressSync(
|
|
133
170
|
this.programs.mMint,
|
|
134
|
-
|
|
135
|
-
[Buffer.from("token_authority")],
|
|
136
|
-
this.ntt.program.programId
|
|
137
|
-
)[0],
|
|
171
|
+
tokenAuth,
|
|
138
172
|
true,
|
|
139
173
|
splToken.TOKEN_2022_PROGRAM_ID
|
|
140
174
|
),
|
|
@@ -185,24 +219,13 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
185
219
|
},
|
|
186
220
|
{
|
|
187
221
|
// session auth
|
|
188
|
-
pubkey:
|
|
189
|
-
amount: new BN__default.default(amount2),
|
|
190
|
-
recipientChain: {
|
|
191
|
-
id: 2
|
|
192
|
-
// Ethereum
|
|
193
|
-
},
|
|
194
|
-
recipientAddress: [...Array(32)],
|
|
195
|
-
shouldQueue: false
|
|
196
|
-
}),
|
|
222
|
+
pubkey: sessionAuth,
|
|
197
223
|
isSigner: false,
|
|
198
224
|
isWritable: false
|
|
199
225
|
},
|
|
200
226
|
{
|
|
201
227
|
// token auth
|
|
202
|
-
pubkey:
|
|
203
|
-
[Buffer.from("token_authority")],
|
|
204
|
-
this.ntt.program.programId
|
|
205
|
-
)[0],
|
|
228
|
+
pubkey: tokenAuth,
|
|
206
229
|
isSigner: false,
|
|
207
230
|
isWritable: false
|
|
208
231
|
},
|
|
@@ -309,10 +332,79 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
309
332
|
// chain_id
|
|
310
333
|
recipientAddress,
|
|
311
334
|
// recipient_address
|
|
312
|
-
|
|
313
|
-
// destination_token
|
|
314
|
-
Buffer.from([Number(shouldQueue)])
|
|
335
|
+
Buffer.from([Number(shouldQueue)]),
|
|
315
336
|
// should_queue
|
|
337
|
+
destinationToken
|
|
338
|
+
// destination_token
|
|
339
|
+
])
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
async getExecutorRelayIx(sender, quote, destinationChain) {
|
|
343
|
+
const emitter = web3_js.PublicKey.findProgramAddressSync(
|
|
344
|
+
[Buffer.from("emitter")],
|
|
345
|
+
this.ntt.program.programId
|
|
346
|
+
)[0];
|
|
347
|
+
const bridgeSequence = web3_js.PublicKey.findProgramAddressSync(
|
|
348
|
+
[Buffer.from("Sequence"), emitter.toBytes()],
|
|
349
|
+
new web3_js.PublicKey(this.ntt.contracts.coreBridge)
|
|
350
|
+
)[0];
|
|
351
|
+
const info = await this.ntt.connection.getAccountInfo(bridgeSequence);
|
|
352
|
+
const sequence = new BN__default.default(info.data, "le");
|
|
353
|
+
const vaaReqBytes = Buffer.concat([
|
|
354
|
+
Buffer.from("ERV1"),
|
|
355
|
+
// type
|
|
356
|
+
new BN__default.default(sdkConnect.chainToChainId(this.ntt.chain)).toArrayLike(Buffer, "be", 2),
|
|
357
|
+
// emitter chain
|
|
358
|
+
emitter.toBuffer(),
|
|
359
|
+
// emitter address
|
|
360
|
+
sequence.toArrayLike(Buffer, "be", 8)
|
|
361
|
+
// sequence
|
|
362
|
+
]);
|
|
363
|
+
const signedQuoteBytes = Buffer.from(quote.signedQuote);
|
|
364
|
+
const relayInstructions = Buffer.from(quote.relayInstructions);
|
|
365
|
+
return new web3_js.TransactionInstruction({
|
|
366
|
+
keys: [
|
|
367
|
+
{
|
|
368
|
+
pubkey: sender,
|
|
369
|
+
isSigner: true,
|
|
370
|
+
isWritable: true
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
// payee
|
|
374
|
+
pubkey: new web3_js.PublicKey(quote.payeeAddress),
|
|
375
|
+
isSigner: false,
|
|
376
|
+
isWritable: true
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
pubkey: web3_js.SystemProgram.programId,
|
|
380
|
+
isSigner: false,
|
|
381
|
+
isWritable: false
|
|
382
|
+
}
|
|
383
|
+
],
|
|
384
|
+
programId: new web3_js.PublicKey("execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV"),
|
|
385
|
+
data: Buffer.concat([
|
|
386
|
+
Buffer.from(sha2.sha256("global:request_for_execution").subarray(0, 8)),
|
|
387
|
+
// [109, 107, 87, 37, 151, 192, 119, 115]
|
|
388
|
+
new BN__default.default(quote.estimatedCost.toString()).toArrayLike(Buffer, "le", 8),
|
|
389
|
+
// amount
|
|
390
|
+
new BN__default.default(sdkConnect.chainToChainId(destinationChain)).toArrayLike(Buffer, "le", 2),
|
|
391
|
+
// dst_chain
|
|
392
|
+
this.ntt.program.programId.toBuffer(),
|
|
393
|
+
// peer portal address
|
|
394
|
+
sender.toBuffer(),
|
|
395
|
+
// refund_addr
|
|
396
|
+
new BN__default.default(signedQuoteBytes.length).toArrayLike(Buffer, "le", 4),
|
|
397
|
+
// vec length
|
|
398
|
+
signedQuoteBytes,
|
|
399
|
+
// signed_quote_bytes
|
|
400
|
+
new BN__default.default(vaaReqBytes.length).toArrayLike(Buffer, "le", 4),
|
|
401
|
+
// vec length
|
|
402
|
+
vaaReqBytes,
|
|
403
|
+
// request_bytes
|
|
404
|
+
new BN__default.default(relayInstructions.length).toArrayLike(Buffer, "le", 4),
|
|
405
|
+
// vec length
|
|
406
|
+
relayInstructions
|
|
407
|
+
// relay_instructions
|
|
316
408
|
])
|
|
317
409
|
});
|
|
318
410
|
}
|
|
@@ -577,6 +669,62 @@ function pk(address) {
|
|
|
577
669
|
return new web3_js.PublicKey(address);
|
|
578
670
|
}
|
|
579
671
|
|
|
672
|
+
// src/executor.ts
|
|
673
|
+
function getExecutorConfig(network = "Mainnet") {
|
|
674
|
+
const svmContracts = SolanaRoutes.getSolanaContracts(network, "Solana");
|
|
675
|
+
const svmChains = ["Solana", "Fogo"];
|
|
676
|
+
const evmChains = network === "Mainnet" ? ["Ethereum", "Optimism", "Arbitrum"] : ["Sepolia", "ArbitrumSepolia", "OptimismSepolia"];
|
|
677
|
+
return {
|
|
678
|
+
ntt: {
|
|
679
|
+
tokens: {
|
|
680
|
+
M0: [
|
|
681
|
+
...svmChains.map((chain) => ({
|
|
682
|
+
chain,
|
|
683
|
+
token: svmContracts.token,
|
|
684
|
+
manager: svmContracts.manager,
|
|
685
|
+
transceiver: [
|
|
686
|
+
{
|
|
687
|
+
type: "wormhole",
|
|
688
|
+
address: svmContracts.transceiver.wormhole
|
|
689
|
+
}
|
|
690
|
+
],
|
|
691
|
+
quoter: svmContracts.quoter
|
|
692
|
+
})),
|
|
693
|
+
...evmChains.map((chain) => ({
|
|
694
|
+
chain,
|
|
695
|
+
token: M0AutomaticRoute.EVM_CONTRACTS.token,
|
|
696
|
+
manager: M0AutomaticRoute.EVM_CONTRACTS.manager,
|
|
697
|
+
transceiver: [
|
|
698
|
+
{
|
|
699
|
+
type: "wormhole",
|
|
700
|
+
address: M0AutomaticRoute.EVM_CONTRACTS.transceiver.wormhole
|
|
701
|
+
}
|
|
702
|
+
],
|
|
703
|
+
quoter: M0AutomaticRoute.EVM_CONTRACTS.quoter
|
|
704
|
+
}))
|
|
705
|
+
]
|
|
706
|
+
}
|
|
707
|
+
},
|
|
708
|
+
referrerFee: {
|
|
709
|
+
feeDbps: 0n,
|
|
710
|
+
perTokenOverrides: {
|
|
711
|
+
// SVM chains require extra compute when receiving messages
|
|
712
|
+
// so we need to override the gas cost
|
|
713
|
+
Solana: {
|
|
714
|
+
[svmContracts.token]: {
|
|
715
|
+
msgValue: 15000000n
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
Fogo: {
|
|
719
|
+
[svmContracts.token]: {
|
|
720
|
+
msgValue: 15000000n
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
|
|
580
728
|
// src/m0AutomaticRoute.ts
|
|
581
729
|
var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.AutomaticRoute {
|
|
582
730
|
static supportedNetworks() {
|
|
@@ -604,21 +752,18 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
604
752
|
static getContracts(chainContext) {
|
|
605
753
|
switch (chainContext.chain) {
|
|
606
754
|
case "Ethereum":
|
|
607
|
-
return this.EVM_CONTRACTS;
|
|
608
755
|
case "Optimism":
|
|
609
|
-
return this.EVM_CONTRACTS;
|
|
610
756
|
case "Arbitrum":
|
|
611
|
-
return this.EVM_CONTRACTS;
|
|
612
757
|
case "Sepolia":
|
|
613
|
-
return this.EVM_CONTRACTS;
|
|
614
758
|
case "OptimismSepolia":
|
|
615
|
-
return this.EVM_CONTRACTS;
|
|
616
759
|
case "ArbitrumSepolia":
|
|
617
760
|
return this.EVM_CONTRACTS;
|
|
618
761
|
case "Solana":
|
|
619
|
-
return SolanaRoutes.getSolanaContracts(chainContext);
|
|
620
762
|
case "Fogo":
|
|
621
|
-
return SolanaRoutes.getSolanaContracts(
|
|
763
|
+
return SolanaRoutes.getSolanaContracts(
|
|
764
|
+
chainContext.network,
|
|
765
|
+
chainContext.chain
|
|
766
|
+
);
|
|
622
767
|
default:
|
|
623
768
|
throw new Error(`Unsupported chain: ${chainContext.chain}`);
|
|
624
769
|
}
|
|
@@ -636,9 +781,11 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
636
781
|
return [];
|
|
637
782
|
}
|
|
638
783
|
const { token: mToken, mLikeTokens } = this.getContracts(toChain);
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
784
|
+
const tokens = mLikeTokens.map((x) => sdkConnect.Wormhole.tokenId(toChain.chain, x));
|
|
785
|
+
if (toChain.chain === "Solana" || toChain.chain === "Fogo") {
|
|
786
|
+
return tokens;
|
|
787
|
+
}
|
|
788
|
+
return [...tokens, sdkConnect.Wormhole.tokenId(toChain.chain, mToken)];
|
|
642
789
|
}
|
|
643
790
|
static isProtocolSupported(chain) {
|
|
644
791
|
return chain.supportsProtocol("Ntt");
|
|
@@ -654,10 +801,6 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
654
801
|
}
|
|
655
802
|
async validate(request, params) {
|
|
656
803
|
const options = params.options ?? this.getDefaultOptions();
|
|
657
|
-
const gasDropoff = sdkConnect.amount.parse(
|
|
658
|
-
options.gasDropoff ?? "0.0",
|
|
659
|
-
request.toChain.config.nativeTokenDecimals
|
|
660
|
-
);
|
|
661
804
|
const parsedAmount = sdkConnect.amount.parse(params.amount, request.source.decimals);
|
|
662
805
|
const trimmedAmount = sdkRouteNtt.NttRoute.trimAmount(
|
|
663
806
|
parsedAmount,
|
|
@@ -673,8 +816,7 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
673
816
|
destinationContracts: toContracts,
|
|
674
817
|
options: {
|
|
675
818
|
queue: false,
|
|
676
|
-
automatic: true
|
|
677
|
-
gasDropoff: sdkConnect.amount.units(gasDropoff)
|
|
819
|
+
automatic: true
|
|
678
820
|
}
|
|
679
821
|
},
|
|
680
822
|
options
|
|
@@ -719,7 +861,7 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
719
861
|
)
|
|
720
862
|
},
|
|
721
863
|
destinationNativeGas: sdkConnect.amount.fromBaseUnits(
|
|
722
|
-
|
|
864
|
+
0n,
|
|
723
865
|
toChain.config.nativeTokenDecimals
|
|
724
866
|
),
|
|
725
867
|
eta: sdkConnect.finality.estimateFinalityTime(request.fromChain.chain)
|
|
@@ -780,18 +922,18 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
780
922
|
*/
|
|
781
923
|
async *transferMLike(ntt, sender, amount2, destination, sourceToken, destinationToken, options) {
|
|
782
924
|
const senderAddress = new sdkEvm.EvmAddress(sender).toString();
|
|
783
|
-
const totalPrice = await ntt.quoteDeliveryPrice(destination.chain, options);
|
|
784
925
|
const tokenContract = sdkEvm.EvmPlatform.getTokenImplementation(
|
|
785
926
|
ntt.provider,
|
|
786
927
|
sourceToken
|
|
787
928
|
);
|
|
929
|
+
const spenderAddress = this.requiresExecutor(destination.chain) ? _M0AutomaticRoute.EXECUTOR_ENTRYPOINT : ntt.managerAddress;
|
|
788
930
|
const allowance = await tokenContract.allowance(
|
|
789
931
|
senderAddress,
|
|
790
|
-
|
|
932
|
+
spenderAddress
|
|
791
933
|
);
|
|
792
934
|
if (allowance < amount2) {
|
|
793
935
|
const txReq2 = await tokenContract.approve.populateTransaction(
|
|
794
|
-
|
|
936
|
+
spenderAddress,
|
|
795
937
|
amount2
|
|
796
938
|
);
|
|
797
939
|
yield this.createUnsignedTx(
|
|
@@ -801,6 +943,36 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
801
943
|
);
|
|
802
944
|
}
|
|
803
945
|
const receiver = sdkConnect.universalAddress(destination);
|
|
946
|
+
if (this.requiresExecutor(destination.chain)) {
|
|
947
|
+
const quote = await this.getExecutorQuote(
|
|
948
|
+
ntt.network,
|
|
949
|
+
ntt.chain,
|
|
950
|
+
destination.chain,
|
|
951
|
+
amount2
|
|
952
|
+
);
|
|
953
|
+
const contract2 = new ethers.Contract(_M0AutomaticRoute.EXECUTOR_ENTRYPOINT, [
|
|
954
|
+
"function transferMLikeToken(uint256 amount, address sourceToken, uint16 destinationChainId, bytes32 destinationToken, bytes32 recipient, bytes32 refundAddress, (uint256 value, address refundAddress, bytes signedQuote, bytes instructions) executorArgs, bytes memory transceiverInstructions) external payable returns (bytes32 messageId)"
|
|
955
|
+
]);
|
|
956
|
+
const executorArgs = {
|
|
957
|
+
value: quote.estimatedCost,
|
|
958
|
+
refundAddress: senderAddress,
|
|
959
|
+
signedQuote: quote.signedQuote,
|
|
960
|
+
instructions: quote.relayInstructions
|
|
961
|
+
};
|
|
962
|
+
const txReq2 = await contract2.getFunction("transferMLikeToken").populateTransaction(
|
|
963
|
+
amount2,
|
|
964
|
+
sourceToken,
|
|
965
|
+
sdkConnect.toChainId(destination.chain),
|
|
966
|
+
sdkConnect.toUniversal(destination.chain, destinationToken).toString(),
|
|
967
|
+
receiver,
|
|
968
|
+
receiver,
|
|
969
|
+
executorArgs,
|
|
970
|
+
Uint8Array.from(Buffer.from("01000101", "hex")),
|
|
971
|
+
{ value: quote.estimatedCost }
|
|
972
|
+
);
|
|
973
|
+
yield ntt.createUnsignedTx(sdkEvm.addFrom(txReq2, senderAddress), "Ntt.transfer");
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
804
976
|
const contract = new ethers.Contract(ntt.managerAddress, [
|
|
805
977
|
"function transferMLikeToken(uint256 amount, address sourceToken, uint16 destinationChainId, bytes32 destinationToken, bytes32 recipient, bytes32 refundAddress) external payable returns (uint64 sequence)"
|
|
806
978
|
]);
|
|
@@ -811,7 +983,7 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
811
983
|
sdkConnect.toUniversal(destination.chain, destinationToken).toString(),
|
|
812
984
|
receiver,
|
|
813
985
|
receiver,
|
|
814
|
-
{ value:
|
|
986
|
+
{ value: await ntt.quoteDeliveryPrice(destination.chain, options) }
|
|
815
987
|
);
|
|
816
988
|
yield ntt.createUnsignedTx(sdkEvm.addFrom(txReq, senderAddress), "Ntt.transfer");
|
|
817
989
|
}
|
|
@@ -826,7 +998,7 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
826
998
|
}
|
|
827
999
|
async *transferSolanaExtension(ntt, sender, amount2, recipient, sourceToken, destinationToken, options, outboxItem) {
|
|
828
1000
|
const router = new SolanaRoutes(ntt);
|
|
829
|
-
if (
|
|
1001
|
+
if (router.getSolanaContracts().token === sourceToken) {
|
|
830
1002
|
return ntt.transfer(sender, amount2, recipient, options);
|
|
831
1003
|
}
|
|
832
1004
|
const config = await ntt.getConfig();
|
|
@@ -861,18 +1033,29 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
861
1033
|
const tx = new web3_js.Transaction();
|
|
862
1034
|
tx.feePayer = payerAddress;
|
|
863
1035
|
tx.add(...ixs);
|
|
864
|
-
if (
|
|
865
|
-
|
|
1036
|
+
if (this.requiresExecutor(recipient.chain)) {
|
|
1037
|
+
const quote = await this.getExecutorQuote(
|
|
1038
|
+
ntt.network,
|
|
1039
|
+
ntt.chain,
|
|
1040
|
+
recipient.chain,
|
|
1041
|
+
amount2
|
|
1042
|
+
);
|
|
1043
|
+
tx.add(
|
|
1044
|
+
await router.getExecutorRelayIx(payerAddress, quote, recipient.chain)
|
|
1045
|
+
);
|
|
1046
|
+
} else if (options.automatic) {
|
|
1047
|
+
if (!ntt.quoter) {
|
|
866
1048
|
throw new Error(
|
|
867
1049
|
"No quoter available, cannot initiate an automatic transfer."
|
|
868
1050
|
);
|
|
1051
|
+
}
|
|
869
1052
|
const fee = await ntt.quoteDeliveryPrice(recipient.chain, options);
|
|
870
1053
|
const relayIx = await ntt.quoter.createRequestRelayInstruction(
|
|
871
1054
|
payerAddress,
|
|
872
1055
|
outboxItem.publicKey,
|
|
873
1056
|
recipient.chain,
|
|
874
1057
|
Number(fee) / web3_js.LAMPORTS_PER_SOL,
|
|
875
|
-
|
|
1058
|
+
0
|
|
876
1059
|
);
|
|
877
1060
|
tx.add(relayIx);
|
|
878
1061
|
}
|
|
@@ -952,11 +1135,44 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends sdkConnect.routes.Automa
|
|
|
952
1135
|
}
|
|
953
1136
|
yield receipt;
|
|
954
1137
|
}
|
|
1138
|
+
async getExecutorQuote(network, sourceChain, destinationChain, amount2) {
|
|
1139
|
+
const wh = new sdkConnect.Wormhole(network, [solana__default.default.Platform, evm__default.default.Platform]);
|
|
1140
|
+
const executorRoute = sdkRouteNtt.nttExecutorRoute(getExecutorConfig(network));
|
|
1141
|
+
const routeInstance = new executorRoute(wh);
|
|
1142
|
+
const resolveM = (chain) => {
|
|
1143
|
+
if (sdkConnect.chainToPlatform(chain) === "Solana") {
|
|
1144
|
+
const c = chain;
|
|
1145
|
+
return SolanaRoutes.getSolanaContracts(network, c).token;
|
|
1146
|
+
}
|
|
1147
|
+
return _M0AutomaticRoute.EVM_CONTRACTS.token;
|
|
1148
|
+
};
|
|
1149
|
+
const transferRequest = await sdkConnect.routes.RouteTransferRequest.create(wh, {
|
|
1150
|
+
source: sdkConnect.Wormhole.tokenId(sourceChain, resolveM(sourceChain)),
|
|
1151
|
+
destination: sdkConnect.Wormhole.tokenId(
|
|
1152
|
+
destinationChain,
|
|
1153
|
+
resolveM(destinationChain)
|
|
1154
|
+
)
|
|
1155
|
+
});
|
|
1156
|
+
const validated = await routeInstance.validate(transferRequest, {
|
|
1157
|
+
amount: amount2.toString()
|
|
1158
|
+
});
|
|
1159
|
+
if (!validated.valid) {
|
|
1160
|
+
throw new Error(`Validation failed: ${validated.error.message}`);
|
|
1161
|
+
}
|
|
1162
|
+
return await routeInstance.fetchExecutorQuote(
|
|
1163
|
+
transferRequest,
|
|
1164
|
+
validated.params
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
requiresExecutor(destination) {
|
|
1168
|
+
return sdkConnect.chainToPlatform(destination) === "Solana";
|
|
1169
|
+
}
|
|
955
1170
|
};
|
|
956
1171
|
// ntt does not support gas drop-off currently
|
|
957
1172
|
_M0AutomaticRoute.NATIVE_GAS_DROPOFF_SUPPORTED = false;
|
|
958
1173
|
// Wrapped M token address is the same on EVM chains
|
|
959
1174
|
_M0AutomaticRoute.EVM_WRAPPED_M_TOKEN = "0x437cc33344a0B27A429f795ff6B469C72698B291";
|
|
1175
|
+
_M0AutomaticRoute.EXECUTOR_ENTRYPOINT = "0x8518040a9cf9dfb55a4f099bb0eaabeefeb03643";
|
|
960
1176
|
// Contract addresses are the same on all EVM chains
|
|
961
1177
|
_M0AutomaticRoute.EVM_CONTRACTS = {
|
|
962
1178
|
// M token address is the same on EVM chains
|
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { routes, Wormhole, isSameToken, amount, finality, chainToPlatform, canonicalAddress, signSendWait, TransferState, universalAddress, toChainId, toUniversal, isSourceInitiated, isSourceFinalized, isAttested, isRedeemed, chainToChainId } from '@wormhole-foundation/sdk-connect';
|
|
2
2
|
import { Ntt } from '@wormhole-foundation/sdk-definitions-ntt';
|
|
3
|
-
import { WEI_PER_GWEI, NTT } from '@wormhole-foundation/sdk-solana-ntt';
|
|
4
3
|
import { EvmAddress, EvmPlatform, addFrom, EvmUnsignedTransaction, addChainId } from '@wormhole-foundation/sdk-evm';
|
|
5
4
|
import { SolanaAddress } from '@wormhole-foundation/sdk-solana';
|
|
6
|
-
import { NttRoute } from '@wormhole-foundation/sdk-route-ntt';
|
|
5
|
+
import { NttRoute, nttExecutorRoute } from '@wormhole-foundation/sdk-route-ntt';
|
|
7
6
|
import { Contract } from 'ethers';
|
|
8
7
|
import { Keypair, PublicKey, Transaction, LAMPORTS_PER_SOL, TransactionMessage, VersionedTransaction, TransactionInstruction, SystemProgram, AddressLookupTableAccount } from '@solana/web3.js';
|
|
9
|
-
import { TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, createAssociatedTokenAccountInstruction } from '@solana/spl-token';
|
|
8
|
+
import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, createAssociatedTokenAccountInstruction } from '@solana/spl-token';
|
|
9
|
+
import { NTT } from '@wormhole-foundation/sdk-solana-ntt';
|
|
10
10
|
import BN from 'bn.js';
|
|
11
11
|
import { sha256 } from '@noble/hashes/sha2';
|
|
12
|
+
import evm from '@wormhole-foundation/sdk/platforms/evm';
|
|
13
|
+
import solana from '@wormhole-foundation/sdk/platforms/solana';
|
|
12
14
|
|
|
13
15
|
// src/m0AutomaticRoute.ts
|
|
14
16
|
var SolanaRoutes = class _SolanaRoutes {
|
|
@@ -16,7 +18,10 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
16
18
|
this.ntt = ntt;
|
|
17
19
|
this.network = ntt.network;
|
|
18
20
|
this.programs = _SolanaRoutes.getPrograms(this.network);
|
|
19
|
-
this.extPrograms = _SolanaRoutes.getExtPrograms(
|
|
21
|
+
this.extPrograms = _SolanaRoutes.getExtPrograms(
|
|
22
|
+
this.network,
|
|
23
|
+
this.ntt.chain
|
|
24
|
+
);
|
|
20
25
|
}
|
|
21
26
|
static getPrograms(network) {
|
|
22
27
|
return {
|
|
@@ -24,7 +29,7 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
24
29
|
swap: pk("MSwapi3WhNKMUGm9YrxGhypgUEt7wYQH3ZgG32XoWzH"),
|
|
25
30
|
earn: pk("mz2vDzjbQDUDXBH6FPF5s4odCJ4y8YLE5QWaZ8XdZ9Z"),
|
|
26
31
|
lut: pk("9JLRqBqkznKiSoNfotA4ywSRdnWb2fE76SiFrAfkaRCD"),
|
|
27
|
-
mMint: pk("
|
|
32
|
+
mMint: pk("mzerojk9tg56ebsrEAhfkyc9VgKjTW2zDqp6C5mhjzH"),
|
|
28
33
|
portal: pk("mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY"),
|
|
29
34
|
quoter: pk("Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ")
|
|
30
35
|
},
|
|
@@ -32,13 +37,21 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
32
37
|
swap: pk("MSwapi3WhNKMUGm9YrxGhypgUEt7wYQH3ZgG32XoWzH"),
|
|
33
38
|
earn: pk("mz2vDzjbQDUDXBH6FPF5s4odCJ4y8YLE5QWaZ8XdZ9Z"),
|
|
34
39
|
lut: pk("6GhuWPuAmiJeeSVsr58KjqHcAejJRndCx9BVtHkaYHUR"),
|
|
35
|
-
mMint: pk("
|
|
40
|
+
mMint: pk("mzerojk9tg56ebsrEAhfkyc9VgKjTW2zDqp6C5mhjzH"),
|
|
36
41
|
portal: pk("mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY"),
|
|
37
42
|
quoter: pk("Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ")
|
|
38
43
|
}
|
|
39
44
|
}[network];
|
|
40
45
|
}
|
|
41
|
-
static getExtPrograms(network) {
|
|
46
|
+
static getExtPrograms(network, chain) {
|
|
47
|
+
if (chain === "Fogo") {
|
|
48
|
+
return {
|
|
49
|
+
fUSDqquEMUU8UmU2YWYGZy2Lda1oMzBc88Mkzc1PRDw: {
|
|
50
|
+
program: pk("extUkDFf3HLekkxbcZ3XRUizMjbxMJgKBay3p9xGVmg"),
|
|
51
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
42
55
|
return {
|
|
43
56
|
Mainnet: {
|
|
44
57
|
mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp: {
|
|
@@ -66,16 +79,19 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
66
79
|
usdkyPPxgV7sfNyKb8eDz66ogPrkRXG3wS2FVb6LLUf: {
|
|
67
80
|
program: pk("3PskKTHgboCbUSQPMcCAZdZNFHbNvSoZ8zEFYANCdob7"),
|
|
68
81
|
tokenProgram: TOKEN_2022_PROGRAM_ID
|
|
82
|
+
},
|
|
83
|
+
fUSDqquEMUU8UmU2YWYGZy2Lda1oMzBc88Mkzc1PRDw: {
|
|
84
|
+
program: pk("extUkDFf3HLekkxbcZ3XRUizMjbxMJgKBay3p9xGVmg"),
|
|
85
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
69
86
|
}
|
|
70
87
|
}
|
|
71
88
|
}[network];
|
|
72
89
|
}
|
|
73
|
-
static getSolanaContracts(
|
|
74
|
-
const programs = _SolanaRoutes.getPrograms(
|
|
75
|
-
chainContext.network
|
|
76
|
-
);
|
|
90
|
+
static getSolanaContracts(network, chain) {
|
|
91
|
+
const programs = _SolanaRoutes.getPrograms(network);
|
|
77
92
|
const extPrograms = _SolanaRoutes.getExtPrograms(
|
|
78
|
-
|
|
93
|
+
network,
|
|
94
|
+
chain
|
|
79
95
|
);
|
|
80
96
|
return {
|
|
81
97
|
token: programs.mMint.toBase58(),
|
|
@@ -85,10 +101,19 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
85
101
|
quoter: programs.quoter.toBase58()
|
|
86
102
|
};
|
|
87
103
|
}
|
|
104
|
+
getSolanaContracts() {
|
|
105
|
+
return _SolanaRoutes.getSolanaContracts(this.network, this.ntt.chain);
|
|
106
|
+
}
|
|
88
107
|
getTransferExtensionBurnIx(amount2, recipient, payer, outboxItem, extMint, destinationToken, shouldQueue = true) {
|
|
89
|
-
const recipientAddress =
|
|
90
|
-
|
|
91
|
-
|
|
108
|
+
const recipientAddress = toUniversal(
|
|
109
|
+
recipient.chain,
|
|
110
|
+
recipient.address.toString()
|
|
111
|
+
).toUint8Array();
|
|
112
|
+
if (recipientAddress.length !== 32) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`recipient address must be 32 bytes, got ${recipientAddress.length} bytes`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
92
117
|
if (destinationToken.length !== 32) {
|
|
93
118
|
throw new Error(
|
|
94
119
|
`destinationToken must be 32 bytes, got ${destinationToken.length} bytes`
|
|
@@ -101,6 +126,16 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
101
126
|
);
|
|
102
127
|
}
|
|
103
128
|
const { program: extProgram, tokenProgram: extTokenProgram } = extension;
|
|
129
|
+
const [tokenAuth] = PublicKey.findProgramAddressSync(
|
|
130
|
+
[Buffer.from("token_authority")],
|
|
131
|
+
this.programs.portal
|
|
132
|
+
);
|
|
133
|
+
const sessionAuth = this.ntt.pdas.sessionAuthority(tokenAuth, {
|
|
134
|
+
amount: new BN(amount2),
|
|
135
|
+
recipientChain: { id: chainToChainId(recipient.chain) },
|
|
136
|
+
recipientAddress: [...recipientAddress],
|
|
137
|
+
shouldQueue
|
|
138
|
+
});
|
|
104
139
|
return new TransactionInstruction({
|
|
105
140
|
programId: this.ntt.program.programId,
|
|
106
141
|
keys: [
|
|
@@ -125,10 +160,7 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
125
160
|
// from (token auth m token account)
|
|
126
161
|
pubkey: getAssociatedTokenAddressSync(
|
|
127
162
|
this.programs.mMint,
|
|
128
|
-
|
|
129
|
-
[Buffer.from("token_authority")],
|
|
130
|
-
this.ntt.program.programId
|
|
131
|
-
)[0],
|
|
163
|
+
tokenAuth,
|
|
132
164
|
true,
|
|
133
165
|
TOKEN_2022_PROGRAM_ID
|
|
134
166
|
),
|
|
@@ -179,24 +211,13 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
179
211
|
},
|
|
180
212
|
{
|
|
181
213
|
// session auth
|
|
182
|
-
pubkey:
|
|
183
|
-
amount: new BN(amount2),
|
|
184
|
-
recipientChain: {
|
|
185
|
-
id: 2
|
|
186
|
-
// Ethereum
|
|
187
|
-
},
|
|
188
|
-
recipientAddress: [...Array(32)],
|
|
189
|
-
shouldQueue: false
|
|
190
|
-
}),
|
|
214
|
+
pubkey: sessionAuth,
|
|
191
215
|
isSigner: false,
|
|
192
216
|
isWritable: false
|
|
193
217
|
},
|
|
194
218
|
{
|
|
195
219
|
// token auth
|
|
196
|
-
pubkey:
|
|
197
|
-
[Buffer.from("token_authority")],
|
|
198
|
-
this.ntt.program.programId
|
|
199
|
-
)[0],
|
|
220
|
+
pubkey: tokenAuth,
|
|
200
221
|
isSigner: false,
|
|
201
222
|
isWritable: false
|
|
202
223
|
},
|
|
@@ -303,10 +324,79 @@ var SolanaRoutes = class _SolanaRoutes {
|
|
|
303
324
|
// chain_id
|
|
304
325
|
recipientAddress,
|
|
305
326
|
// recipient_address
|
|
306
|
-
|
|
307
|
-
// destination_token
|
|
308
|
-
Buffer.from([Number(shouldQueue)])
|
|
327
|
+
Buffer.from([Number(shouldQueue)]),
|
|
309
328
|
// should_queue
|
|
329
|
+
destinationToken
|
|
330
|
+
// destination_token
|
|
331
|
+
])
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
async getExecutorRelayIx(sender, quote, destinationChain) {
|
|
335
|
+
const emitter = PublicKey.findProgramAddressSync(
|
|
336
|
+
[Buffer.from("emitter")],
|
|
337
|
+
this.ntt.program.programId
|
|
338
|
+
)[0];
|
|
339
|
+
const bridgeSequence = PublicKey.findProgramAddressSync(
|
|
340
|
+
[Buffer.from("Sequence"), emitter.toBytes()],
|
|
341
|
+
new PublicKey(this.ntt.contracts.coreBridge)
|
|
342
|
+
)[0];
|
|
343
|
+
const info = await this.ntt.connection.getAccountInfo(bridgeSequence);
|
|
344
|
+
const sequence = new BN(info.data, "le");
|
|
345
|
+
const vaaReqBytes = Buffer.concat([
|
|
346
|
+
Buffer.from("ERV1"),
|
|
347
|
+
// type
|
|
348
|
+
new BN(chainToChainId(this.ntt.chain)).toArrayLike(Buffer, "be", 2),
|
|
349
|
+
// emitter chain
|
|
350
|
+
emitter.toBuffer(),
|
|
351
|
+
// emitter address
|
|
352
|
+
sequence.toArrayLike(Buffer, "be", 8)
|
|
353
|
+
// sequence
|
|
354
|
+
]);
|
|
355
|
+
const signedQuoteBytes = Buffer.from(quote.signedQuote);
|
|
356
|
+
const relayInstructions = Buffer.from(quote.relayInstructions);
|
|
357
|
+
return new TransactionInstruction({
|
|
358
|
+
keys: [
|
|
359
|
+
{
|
|
360
|
+
pubkey: sender,
|
|
361
|
+
isSigner: true,
|
|
362
|
+
isWritable: true
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
// payee
|
|
366
|
+
pubkey: new PublicKey(quote.payeeAddress),
|
|
367
|
+
isSigner: false,
|
|
368
|
+
isWritable: true
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
pubkey: SystemProgram.programId,
|
|
372
|
+
isSigner: false,
|
|
373
|
+
isWritable: false
|
|
374
|
+
}
|
|
375
|
+
],
|
|
376
|
+
programId: new PublicKey("execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV"),
|
|
377
|
+
data: Buffer.concat([
|
|
378
|
+
Buffer.from(sha256("global:request_for_execution").subarray(0, 8)),
|
|
379
|
+
// [109, 107, 87, 37, 151, 192, 119, 115]
|
|
380
|
+
new BN(quote.estimatedCost.toString()).toArrayLike(Buffer, "le", 8),
|
|
381
|
+
// amount
|
|
382
|
+
new BN(chainToChainId(destinationChain)).toArrayLike(Buffer, "le", 2),
|
|
383
|
+
// dst_chain
|
|
384
|
+
this.ntt.program.programId.toBuffer(),
|
|
385
|
+
// peer portal address
|
|
386
|
+
sender.toBuffer(),
|
|
387
|
+
// refund_addr
|
|
388
|
+
new BN(signedQuoteBytes.length).toArrayLike(Buffer, "le", 4),
|
|
389
|
+
// vec length
|
|
390
|
+
signedQuoteBytes,
|
|
391
|
+
// signed_quote_bytes
|
|
392
|
+
new BN(vaaReqBytes.length).toArrayLike(Buffer, "le", 4),
|
|
393
|
+
// vec length
|
|
394
|
+
vaaReqBytes,
|
|
395
|
+
// request_bytes
|
|
396
|
+
new BN(relayInstructions.length).toArrayLike(Buffer, "le", 4),
|
|
397
|
+
// vec length
|
|
398
|
+
relayInstructions
|
|
399
|
+
// relay_instructions
|
|
310
400
|
])
|
|
311
401
|
});
|
|
312
402
|
}
|
|
@@ -571,6 +661,62 @@ function pk(address) {
|
|
|
571
661
|
return new PublicKey(address);
|
|
572
662
|
}
|
|
573
663
|
|
|
664
|
+
// src/executor.ts
|
|
665
|
+
function getExecutorConfig(network = "Mainnet") {
|
|
666
|
+
const svmContracts = SolanaRoutes.getSolanaContracts(network, "Solana");
|
|
667
|
+
const svmChains = ["Solana", "Fogo"];
|
|
668
|
+
const evmChains = network === "Mainnet" ? ["Ethereum", "Optimism", "Arbitrum"] : ["Sepolia", "ArbitrumSepolia", "OptimismSepolia"];
|
|
669
|
+
return {
|
|
670
|
+
ntt: {
|
|
671
|
+
tokens: {
|
|
672
|
+
M0: [
|
|
673
|
+
...svmChains.map((chain) => ({
|
|
674
|
+
chain,
|
|
675
|
+
token: svmContracts.token,
|
|
676
|
+
manager: svmContracts.manager,
|
|
677
|
+
transceiver: [
|
|
678
|
+
{
|
|
679
|
+
type: "wormhole",
|
|
680
|
+
address: svmContracts.transceiver.wormhole
|
|
681
|
+
}
|
|
682
|
+
],
|
|
683
|
+
quoter: svmContracts.quoter
|
|
684
|
+
})),
|
|
685
|
+
...evmChains.map((chain) => ({
|
|
686
|
+
chain,
|
|
687
|
+
token: M0AutomaticRoute.EVM_CONTRACTS.token,
|
|
688
|
+
manager: M0AutomaticRoute.EVM_CONTRACTS.manager,
|
|
689
|
+
transceiver: [
|
|
690
|
+
{
|
|
691
|
+
type: "wormhole",
|
|
692
|
+
address: M0AutomaticRoute.EVM_CONTRACTS.transceiver.wormhole
|
|
693
|
+
}
|
|
694
|
+
],
|
|
695
|
+
quoter: M0AutomaticRoute.EVM_CONTRACTS.quoter
|
|
696
|
+
}))
|
|
697
|
+
]
|
|
698
|
+
}
|
|
699
|
+
},
|
|
700
|
+
referrerFee: {
|
|
701
|
+
feeDbps: 0n,
|
|
702
|
+
perTokenOverrides: {
|
|
703
|
+
// SVM chains require extra compute when receiving messages
|
|
704
|
+
// so we need to override the gas cost
|
|
705
|
+
Solana: {
|
|
706
|
+
[svmContracts.token]: {
|
|
707
|
+
msgValue: 15000000n
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
Fogo: {
|
|
711
|
+
[svmContracts.token]: {
|
|
712
|
+
msgValue: 15000000n
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
|
|
574
720
|
// src/m0AutomaticRoute.ts
|
|
575
721
|
var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
576
722
|
static supportedNetworks() {
|
|
@@ -598,21 +744,18 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
598
744
|
static getContracts(chainContext) {
|
|
599
745
|
switch (chainContext.chain) {
|
|
600
746
|
case "Ethereum":
|
|
601
|
-
return this.EVM_CONTRACTS;
|
|
602
747
|
case "Optimism":
|
|
603
|
-
return this.EVM_CONTRACTS;
|
|
604
748
|
case "Arbitrum":
|
|
605
|
-
return this.EVM_CONTRACTS;
|
|
606
749
|
case "Sepolia":
|
|
607
|
-
return this.EVM_CONTRACTS;
|
|
608
750
|
case "OptimismSepolia":
|
|
609
|
-
return this.EVM_CONTRACTS;
|
|
610
751
|
case "ArbitrumSepolia":
|
|
611
752
|
return this.EVM_CONTRACTS;
|
|
612
753
|
case "Solana":
|
|
613
|
-
return SolanaRoutes.getSolanaContracts(chainContext);
|
|
614
754
|
case "Fogo":
|
|
615
|
-
return SolanaRoutes.getSolanaContracts(
|
|
755
|
+
return SolanaRoutes.getSolanaContracts(
|
|
756
|
+
chainContext.network,
|
|
757
|
+
chainContext.chain
|
|
758
|
+
);
|
|
616
759
|
default:
|
|
617
760
|
throw new Error(`Unsupported chain: ${chainContext.chain}`);
|
|
618
761
|
}
|
|
@@ -630,9 +773,11 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
630
773
|
return [];
|
|
631
774
|
}
|
|
632
775
|
const { token: mToken, mLikeTokens } = this.getContracts(toChain);
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
776
|
+
const tokens = mLikeTokens.map((x) => Wormhole.tokenId(toChain.chain, x));
|
|
777
|
+
if (toChain.chain === "Solana" || toChain.chain === "Fogo") {
|
|
778
|
+
return tokens;
|
|
779
|
+
}
|
|
780
|
+
return [...tokens, Wormhole.tokenId(toChain.chain, mToken)];
|
|
636
781
|
}
|
|
637
782
|
static isProtocolSupported(chain) {
|
|
638
783
|
return chain.supportsProtocol("Ntt");
|
|
@@ -648,10 +793,6 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
648
793
|
}
|
|
649
794
|
async validate(request, params) {
|
|
650
795
|
const options = params.options ?? this.getDefaultOptions();
|
|
651
|
-
const gasDropoff = amount.parse(
|
|
652
|
-
options.gasDropoff ?? "0.0",
|
|
653
|
-
request.toChain.config.nativeTokenDecimals
|
|
654
|
-
);
|
|
655
796
|
const parsedAmount = amount.parse(params.amount, request.source.decimals);
|
|
656
797
|
const trimmedAmount = NttRoute.trimAmount(
|
|
657
798
|
parsedAmount,
|
|
@@ -667,8 +808,7 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
667
808
|
destinationContracts: toContracts,
|
|
668
809
|
options: {
|
|
669
810
|
queue: false,
|
|
670
|
-
automatic: true
|
|
671
|
-
gasDropoff: amount.units(gasDropoff)
|
|
811
|
+
automatic: true
|
|
672
812
|
}
|
|
673
813
|
},
|
|
674
814
|
options
|
|
@@ -713,7 +853,7 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
713
853
|
)
|
|
714
854
|
},
|
|
715
855
|
destinationNativeGas: amount.fromBaseUnits(
|
|
716
|
-
|
|
856
|
+
0n,
|
|
717
857
|
toChain.config.nativeTokenDecimals
|
|
718
858
|
),
|
|
719
859
|
eta: finality.estimateFinalityTime(request.fromChain.chain)
|
|
@@ -774,18 +914,18 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
774
914
|
*/
|
|
775
915
|
async *transferMLike(ntt, sender, amount2, destination, sourceToken, destinationToken, options) {
|
|
776
916
|
const senderAddress = new EvmAddress(sender).toString();
|
|
777
|
-
const totalPrice = await ntt.quoteDeliveryPrice(destination.chain, options);
|
|
778
917
|
const tokenContract = EvmPlatform.getTokenImplementation(
|
|
779
918
|
ntt.provider,
|
|
780
919
|
sourceToken
|
|
781
920
|
);
|
|
921
|
+
const spenderAddress = this.requiresExecutor(destination.chain) ? _M0AutomaticRoute.EXECUTOR_ENTRYPOINT : ntt.managerAddress;
|
|
782
922
|
const allowance = await tokenContract.allowance(
|
|
783
923
|
senderAddress,
|
|
784
|
-
|
|
924
|
+
spenderAddress
|
|
785
925
|
);
|
|
786
926
|
if (allowance < amount2) {
|
|
787
927
|
const txReq2 = await tokenContract.approve.populateTransaction(
|
|
788
|
-
|
|
928
|
+
spenderAddress,
|
|
789
929
|
amount2
|
|
790
930
|
);
|
|
791
931
|
yield this.createUnsignedTx(
|
|
@@ -795,6 +935,36 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
795
935
|
);
|
|
796
936
|
}
|
|
797
937
|
const receiver = universalAddress(destination);
|
|
938
|
+
if (this.requiresExecutor(destination.chain)) {
|
|
939
|
+
const quote = await this.getExecutorQuote(
|
|
940
|
+
ntt.network,
|
|
941
|
+
ntt.chain,
|
|
942
|
+
destination.chain,
|
|
943
|
+
amount2
|
|
944
|
+
);
|
|
945
|
+
const contract2 = new Contract(_M0AutomaticRoute.EXECUTOR_ENTRYPOINT, [
|
|
946
|
+
"function transferMLikeToken(uint256 amount, address sourceToken, uint16 destinationChainId, bytes32 destinationToken, bytes32 recipient, bytes32 refundAddress, (uint256 value, address refundAddress, bytes signedQuote, bytes instructions) executorArgs, bytes memory transceiverInstructions) external payable returns (bytes32 messageId)"
|
|
947
|
+
]);
|
|
948
|
+
const executorArgs = {
|
|
949
|
+
value: quote.estimatedCost,
|
|
950
|
+
refundAddress: senderAddress,
|
|
951
|
+
signedQuote: quote.signedQuote,
|
|
952
|
+
instructions: quote.relayInstructions
|
|
953
|
+
};
|
|
954
|
+
const txReq2 = await contract2.getFunction("transferMLikeToken").populateTransaction(
|
|
955
|
+
amount2,
|
|
956
|
+
sourceToken,
|
|
957
|
+
toChainId(destination.chain),
|
|
958
|
+
toUniversal(destination.chain, destinationToken).toString(),
|
|
959
|
+
receiver,
|
|
960
|
+
receiver,
|
|
961
|
+
executorArgs,
|
|
962
|
+
Uint8Array.from(Buffer.from("01000101", "hex")),
|
|
963
|
+
{ value: quote.estimatedCost }
|
|
964
|
+
);
|
|
965
|
+
yield ntt.createUnsignedTx(addFrom(txReq2, senderAddress), "Ntt.transfer");
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
798
968
|
const contract = new Contract(ntt.managerAddress, [
|
|
799
969
|
"function transferMLikeToken(uint256 amount, address sourceToken, uint16 destinationChainId, bytes32 destinationToken, bytes32 recipient, bytes32 refundAddress) external payable returns (uint64 sequence)"
|
|
800
970
|
]);
|
|
@@ -805,7 +975,7 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
805
975
|
toUniversal(destination.chain, destinationToken).toString(),
|
|
806
976
|
receiver,
|
|
807
977
|
receiver,
|
|
808
|
-
{ value:
|
|
978
|
+
{ value: await ntt.quoteDeliveryPrice(destination.chain, options) }
|
|
809
979
|
);
|
|
810
980
|
yield ntt.createUnsignedTx(addFrom(txReq, senderAddress), "Ntt.transfer");
|
|
811
981
|
}
|
|
@@ -820,7 +990,7 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
820
990
|
}
|
|
821
991
|
async *transferSolanaExtension(ntt, sender, amount2, recipient, sourceToken, destinationToken, options, outboxItem) {
|
|
822
992
|
const router = new SolanaRoutes(ntt);
|
|
823
|
-
if (
|
|
993
|
+
if (router.getSolanaContracts().token === sourceToken) {
|
|
824
994
|
return ntt.transfer(sender, amount2, recipient, options);
|
|
825
995
|
}
|
|
826
996
|
const config = await ntt.getConfig();
|
|
@@ -855,18 +1025,29 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
855
1025
|
const tx = new Transaction();
|
|
856
1026
|
tx.feePayer = payerAddress;
|
|
857
1027
|
tx.add(...ixs);
|
|
858
|
-
if (
|
|
859
|
-
|
|
1028
|
+
if (this.requiresExecutor(recipient.chain)) {
|
|
1029
|
+
const quote = await this.getExecutorQuote(
|
|
1030
|
+
ntt.network,
|
|
1031
|
+
ntt.chain,
|
|
1032
|
+
recipient.chain,
|
|
1033
|
+
amount2
|
|
1034
|
+
);
|
|
1035
|
+
tx.add(
|
|
1036
|
+
await router.getExecutorRelayIx(payerAddress, quote, recipient.chain)
|
|
1037
|
+
);
|
|
1038
|
+
} else if (options.automatic) {
|
|
1039
|
+
if (!ntt.quoter) {
|
|
860
1040
|
throw new Error(
|
|
861
1041
|
"No quoter available, cannot initiate an automatic transfer."
|
|
862
1042
|
);
|
|
1043
|
+
}
|
|
863
1044
|
const fee = await ntt.quoteDeliveryPrice(recipient.chain, options);
|
|
864
1045
|
const relayIx = await ntt.quoter.createRequestRelayInstruction(
|
|
865
1046
|
payerAddress,
|
|
866
1047
|
outboxItem.publicKey,
|
|
867
1048
|
recipient.chain,
|
|
868
1049
|
Number(fee) / LAMPORTS_PER_SOL,
|
|
869
|
-
|
|
1050
|
+
0
|
|
870
1051
|
);
|
|
871
1052
|
tx.add(relayIx);
|
|
872
1053
|
}
|
|
@@ -946,11 +1127,44 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
946
1127
|
}
|
|
947
1128
|
yield receipt;
|
|
948
1129
|
}
|
|
1130
|
+
async getExecutorQuote(network, sourceChain, destinationChain, amount2) {
|
|
1131
|
+
const wh = new Wormhole(network, [solana.Platform, evm.Platform]);
|
|
1132
|
+
const executorRoute = nttExecutorRoute(getExecutorConfig(network));
|
|
1133
|
+
const routeInstance = new executorRoute(wh);
|
|
1134
|
+
const resolveM = (chain) => {
|
|
1135
|
+
if (chainToPlatform(chain) === "Solana") {
|
|
1136
|
+
const c = chain;
|
|
1137
|
+
return SolanaRoutes.getSolanaContracts(network, c).token;
|
|
1138
|
+
}
|
|
1139
|
+
return _M0AutomaticRoute.EVM_CONTRACTS.token;
|
|
1140
|
+
};
|
|
1141
|
+
const transferRequest = await routes.RouteTransferRequest.create(wh, {
|
|
1142
|
+
source: Wormhole.tokenId(sourceChain, resolveM(sourceChain)),
|
|
1143
|
+
destination: Wormhole.tokenId(
|
|
1144
|
+
destinationChain,
|
|
1145
|
+
resolveM(destinationChain)
|
|
1146
|
+
)
|
|
1147
|
+
});
|
|
1148
|
+
const validated = await routeInstance.validate(transferRequest, {
|
|
1149
|
+
amount: amount2.toString()
|
|
1150
|
+
});
|
|
1151
|
+
if (!validated.valid) {
|
|
1152
|
+
throw new Error(`Validation failed: ${validated.error.message}`);
|
|
1153
|
+
}
|
|
1154
|
+
return await routeInstance.fetchExecutorQuote(
|
|
1155
|
+
transferRequest,
|
|
1156
|
+
validated.params
|
|
1157
|
+
);
|
|
1158
|
+
}
|
|
1159
|
+
requiresExecutor(destination) {
|
|
1160
|
+
return chainToPlatform(destination) === "Solana";
|
|
1161
|
+
}
|
|
949
1162
|
};
|
|
950
1163
|
// ntt does not support gas drop-off currently
|
|
951
1164
|
_M0AutomaticRoute.NATIVE_GAS_DROPOFF_SUPPORTED = false;
|
|
952
1165
|
// Wrapped M token address is the same on EVM chains
|
|
953
1166
|
_M0AutomaticRoute.EVM_WRAPPED_M_TOKEN = "0x437cc33344a0B27A429f795ff6B469C72698B291";
|
|
1167
|
+
_M0AutomaticRoute.EXECUTOR_ENTRYPOINT = "0x8518040a9cf9dfb55a4f099bb0eaabeefeb03643";
|
|
954
1168
|
// Contract addresses are the same on all EVM chains
|
|
955
1169
|
_M0AutomaticRoute.EVM_CONTRACTS = {
|
|
956
1170
|
// M token address is the same on EVM chains
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m0-foundation/ntt-sdk-route",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"exports": {
|
|
5
5
|
".": {
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -20,34 +20,35 @@
|
|
|
20
20
|
"files": [
|
|
21
21
|
"dist"
|
|
22
22
|
],
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build": "$npm_execpath tsup --clean",
|
|
25
|
-
"clean": "rm -rf dist"
|
|
26
|
-
},
|
|
27
23
|
"devDependencies": {
|
|
28
24
|
"@changesets/cli": "^2.28.1",
|
|
29
25
|
"@types/bn.js": "^5.2.0",
|
|
30
26
|
"@types/node": "~20.17.17",
|
|
27
|
+
"ts-node": "^10.9.2",
|
|
31
28
|
"tsup": "~8.3.6",
|
|
32
29
|
"typescript": "~5.6.3"
|
|
33
30
|
},
|
|
34
31
|
"publishConfig": {
|
|
35
32
|
"access": "public"
|
|
36
33
|
},
|
|
37
|
-
"packageManager": "pnpm@10.2.0",
|
|
38
34
|
"dependencies": {
|
|
39
35
|
"@noble/hashes": "^1.8.0",
|
|
40
36
|
"@solana/spl-token": "^0.4.13",
|
|
41
37
|
"@solana/web3.js": "^1.98.2",
|
|
42
|
-
"@wormhole-foundation/sdk": "
|
|
43
|
-
"@wormhole-foundation/sdk-connect": "
|
|
44
|
-
"@wormhole-foundation/sdk-definitions-ntt": "
|
|
45
|
-
"@wormhole-foundation/sdk-evm": "
|
|
46
|
-
"@wormhole-foundation/sdk-evm-ntt": "
|
|
47
|
-
"@wormhole-foundation/sdk-route-ntt": "
|
|
48
|
-
"@wormhole-foundation/sdk-solana": "
|
|
49
|
-
"@wormhole-foundation/sdk-solana-ntt": "
|
|
38
|
+
"@wormhole-foundation/sdk": "3.4.7",
|
|
39
|
+
"@wormhole-foundation/sdk-connect": "3.4.7",
|
|
40
|
+
"@wormhole-foundation/sdk-definitions-ntt": "2.0.5",
|
|
41
|
+
"@wormhole-foundation/sdk-evm": "3.4.7",
|
|
42
|
+
"@wormhole-foundation/sdk-evm-ntt": "2.0.5",
|
|
43
|
+
"@wormhole-foundation/sdk-route-ntt": "2.0.5",
|
|
44
|
+
"@wormhole-foundation/sdk-solana": "3.4.7",
|
|
45
|
+
"@wormhole-foundation/sdk-solana-ntt": "2.0.5",
|
|
50
46
|
"bn.js": "^5.2.2",
|
|
51
47
|
"ethers": "^6.5.1"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "$npm_execpath tsup --clean",
|
|
51
|
+
"clean": "rm -rf dist",
|
|
52
|
+
"test-bridge": "node --env-file=.env -r ts-node/register scripts/bridge.ts"
|
|
52
53
|
}
|
|
53
|
-
}
|
|
54
|
+
}
|