@m0-foundation/ntt-sdk-route 0.0.9 → 0.0.11
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 +33 -4
- package/dist/index.d.ts +33 -4
- package/dist/index.js +668 -20
- package/dist/index.mjs +665 -22
- package/package.json +13 -7
package/dist/index.mjs
CHANGED
|
@@ -1,23 +1,564 @@
|
|
|
1
|
-
import { routes, Wormhole, isSameToken,
|
|
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 '@wormhole-foundation/sdk-solana-ntt';
|
|
3
|
+
import { WEI_PER_GWEI, NTT } from '@wormhole-foundation/sdk-solana-ntt';
|
|
4
4
|
import { EvmAddress, EvmPlatform, addFrom, EvmUnsignedTransaction, addChainId } from '@wormhole-foundation/sdk-evm';
|
|
5
|
-
import '@wormhole-foundation/sdk-solana';
|
|
5
|
+
import { SolanaAddress } from '@wormhole-foundation/sdk-solana';
|
|
6
6
|
import { NttRoute } from '@wormhole-foundation/sdk-route-ntt';
|
|
7
7
|
import { Contract } from 'ethers';
|
|
8
|
+
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';
|
|
10
|
+
import BN from 'bn.js';
|
|
11
|
+
import { sha256 } from '@noble/hashes/sha2';
|
|
8
12
|
|
|
9
13
|
// src/m0AutomaticRoute.ts
|
|
10
|
-
var
|
|
11
|
-
|
|
14
|
+
var SolanaRoutes = class _SolanaRoutes {
|
|
15
|
+
constructor(ntt) {
|
|
16
|
+
this.ntt = ntt;
|
|
17
|
+
this.network = ntt.network;
|
|
18
|
+
this.programs = _SolanaRoutes.getPrograms(this.network);
|
|
19
|
+
this.extPrograms = _SolanaRoutes.getExtPrograms(this.network);
|
|
20
|
+
}
|
|
21
|
+
static getPrograms(network) {
|
|
22
|
+
return {
|
|
23
|
+
Mainnet: {
|
|
24
|
+
swap: pk("MSwapi3WhNKMUGm9YrxGhypgUEt7wYQH3ZgG32XoWzH"),
|
|
25
|
+
earn: pk("mz2vDzjbQDUDXBH6FPF5s4odCJ4y8YLE5QWaZ8XdZ9Z"),
|
|
26
|
+
lut: pk("9JLRqBqkznKiSoNfotA4ywSRdnWb2fE76SiFrAfkaRCD"),
|
|
27
|
+
mMint: pk("mzerokyEX9TNDoK4o2YZQBDmMzjokAeN6M2g2S3pLJo"),
|
|
28
|
+
portal: pk("mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY"),
|
|
29
|
+
quoter: pk("Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ")
|
|
30
|
+
},
|
|
31
|
+
Testnet: {
|
|
32
|
+
swap: pk("MSwapi3WhNKMUGm9YrxGhypgUEt7wYQH3ZgG32XoWzH"),
|
|
33
|
+
earn: pk("mz2vDzjbQDUDXBH6FPF5s4odCJ4y8YLE5QWaZ8XdZ9Z"),
|
|
34
|
+
lut: pk("6GhuWPuAmiJeeSVsr58KjqHcAejJRndCx9BVtHkaYHUR"),
|
|
35
|
+
mMint: pk("mzeroZRGCah3j5xEWp2Nih3GDejSBbH1rbHoxDg8By6"),
|
|
36
|
+
portal: pk("mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY"),
|
|
37
|
+
quoter: pk("Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ")
|
|
38
|
+
}
|
|
39
|
+
}[network];
|
|
40
|
+
}
|
|
41
|
+
static getExtPrograms(network) {
|
|
42
|
+
return {
|
|
43
|
+
Mainnet: {
|
|
44
|
+
mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp: {
|
|
45
|
+
program: pk("wMXX1K1nca5W4pZr1piETe78gcAVVrEFi9f4g46uXko"),
|
|
46
|
+
tokenProgram: TOKEN_2022_PROGRAM_ID
|
|
47
|
+
},
|
|
48
|
+
usdkbee86pkLyRmxfFCdkyySpxRb5ndCxVsK2BkRXwX: {
|
|
49
|
+
program: pk("extaykYu5AQcDm3qZAbiDN3yp6skqn6Nssj7veUUGZw"),
|
|
50
|
+
tokenProgram: TOKEN_2022_PROGRAM_ID
|
|
51
|
+
},
|
|
52
|
+
usdkyPPxgV7sfNyKb8eDz66ogPrkRXG3wS2FVb6LLUf: {
|
|
53
|
+
program: pk("extMahs9bUFMYcviKCvnSRaXgs5PcqmMzcnHRtTqE85"),
|
|
54
|
+
tokenProgram: TOKEN_2022_PROGRAM_ID
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
Testnet: {
|
|
58
|
+
mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp: {
|
|
59
|
+
program: pk("wMXX1K1nca5W4pZr1piETe78gcAVVrEFi9f4g46uXko"),
|
|
60
|
+
tokenProgram: TOKEN_2022_PROGRAM_ID
|
|
61
|
+
},
|
|
62
|
+
usdkbee86pkLyRmxfFCdkyySpxRb5ndCxVsK2BkRXwX: {
|
|
63
|
+
program: pk("Fb2AsCKmPd4gKhabT6KsremSHMrJ8G2Mopnc6rDQZX9e"),
|
|
64
|
+
tokenProgram: TOKEN_2022_PROGRAM_ID
|
|
65
|
+
},
|
|
66
|
+
usdkyPPxgV7sfNyKb8eDz66ogPrkRXG3wS2FVb6LLUf: {
|
|
67
|
+
program: pk("3PskKTHgboCbUSQPMcCAZdZNFHbNvSoZ8zEFYANCdob7"),
|
|
68
|
+
tokenProgram: TOKEN_2022_PROGRAM_ID
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}[network];
|
|
72
|
+
}
|
|
73
|
+
static getSolanaContracts(chainContext) {
|
|
74
|
+
const programs = _SolanaRoutes.getPrograms(
|
|
75
|
+
chainContext.network
|
|
76
|
+
);
|
|
77
|
+
const extPrograms = _SolanaRoutes.getExtPrograms(
|
|
78
|
+
chainContext.network
|
|
79
|
+
);
|
|
12
80
|
return {
|
|
13
|
-
token:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
quoter: "Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ"
|
|
81
|
+
token: programs.mMint.toBase58(),
|
|
82
|
+
mLikeTokens: Object.keys(extPrograms),
|
|
83
|
+
manager: programs.portal.toBase58(),
|
|
84
|
+
transceiver: { wormhole: programs.portal.toBase58() },
|
|
85
|
+
quoter: programs.quoter.toBase58()
|
|
19
86
|
};
|
|
20
87
|
}
|
|
88
|
+
getTransferExtensionBurnIx(amount2, recipient, payer, outboxItem, extMint, destinationToken, shouldQueue = true) {
|
|
89
|
+
const recipientAddress = Buffer.alloc(32);
|
|
90
|
+
const dest = Buffer.from(recipient.address.toUint8Array());
|
|
91
|
+
dest.copy(recipientAddress);
|
|
92
|
+
if (destinationToken.length !== 32) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`destinationToken must be 32 bytes, got ${destinationToken.length} bytes`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
const extension = this.extPrograms[extMint.toBase58()];
|
|
98
|
+
if (!extension) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`No extension program found for mint ${extMint.toBase58()}`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
const { program: extProgram, tokenProgram: extTokenProgram } = extension;
|
|
104
|
+
return new TransactionInstruction({
|
|
105
|
+
programId: this.ntt.program.programId,
|
|
106
|
+
keys: [
|
|
107
|
+
{
|
|
108
|
+
pubkey: payer,
|
|
109
|
+
isSigner: true,
|
|
110
|
+
isWritable: true
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
// config
|
|
114
|
+
pubkey: this.ntt.pdas.configAccount(),
|
|
115
|
+
isSigner: false,
|
|
116
|
+
isWritable: false
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
// m mint
|
|
120
|
+
pubkey: this.programs.mMint,
|
|
121
|
+
isSigner: false,
|
|
122
|
+
isWritable: true
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
// from (token auth m token account)
|
|
126
|
+
pubkey: getAssociatedTokenAddressSync(
|
|
127
|
+
this.programs.mMint,
|
|
128
|
+
PublicKey.findProgramAddressSync(
|
|
129
|
+
[Buffer.from("token_authority")],
|
|
130
|
+
this.ntt.program.programId
|
|
131
|
+
)[0],
|
|
132
|
+
true,
|
|
133
|
+
TOKEN_2022_PROGRAM_ID
|
|
134
|
+
),
|
|
135
|
+
isSigner: false,
|
|
136
|
+
isWritable: true
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
// m token program
|
|
140
|
+
pubkey: TOKEN_2022_PROGRAM_ID,
|
|
141
|
+
isSigner: false,
|
|
142
|
+
isWritable: false
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
// outbox item
|
|
146
|
+
pubkey: outboxItem,
|
|
147
|
+
isSigner: true,
|
|
148
|
+
isWritable: true
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
// outbox rate limit
|
|
152
|
+
pubkey: this.ntt.pdas.outboxRateLimitAccount(),
|
|
153
|
+
isSigner: false,
|
|
154
|
+
isWritable: true
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
// custody
|
|
158
|
+
pubkey: this.ntt.config.custody,
|
|
159
|
+
isSigner: false,
|
|
160
|
+
isWritable: true
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
// system program
|
|
164
|
+
pubkey: SystemProgram.programId,
|
|
165
|
+
isSigner: false,
|
|
166
|
+
isWritable: false
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
// inbox rate limit
|
|
170
|
+
pubkey: this.ntt.pdas.inboxRateLimitAccount(recipient.chain),
|
|
171
|
+
isSigner: false,
|
|
172
|
+
isWritable: true
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
// peer
|
|
176
|
+
pubkey: this.ntt.pdas.peerAccount(recipient.chain),
|
|
177
|
+
isSigner: false,
|
|
178
|
+
isWritable: false
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
// session auth
|
|
182
|
+
pubkey: this.ntt.pdas.sessionAuthority(payer, {
|
|
183
|
+
amount: new BN(amount2),
|
|
184
|
+
recipientChain: {
|
|
185
|
+
id: 2
|
|
186
|
+
// Ethereum
|
|
187
|
+
},
|
|
188
|
+
recipientAddress: [...Array(32)],
|
|
189
|
+
shouldQueue: false
|
|
190
|
+
}),
|
|
191
|
+
isSigner: false,
|
|
192
|
+
isWritable: false
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
// token auth
|
|
196
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
197
|
+
[Buffer.from("token_authority")],
|
|
198
|
+
this.ntt.program.programId
|
|
199
|
+
)[0],
|
|
200
|
+
isSigner: false,
|
|
201
|
+
isWritable: false
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
// ext mint
|
|
205
|
+
pubkey: extMint,
|
|
206
|
+
isSigner: false,
|
|
207
|
+
isWritable: true
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
// swap global
|
|
211
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
212
|
+
[Buffer.from("global")],
|
|
213
|
+
this.programs.swap
|
|
214
|
+
)[0],
|
|
215
|
+
isSigner: false,
|
|
216
|
+
isWritable: false
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
// m global
|
|
220
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
221
|
+
[Buffer.from("global")],
|
|
222
|
+
this.programs.earn
|
|
223
|
+
)[0],
|
|
224
|
+
isSigner: false,
|
|
225
|
+
isWritable: false
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
// ext global
|
|
229
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
230
|
+
[Buffer.from("global")],
|
|
231
|
+
extProgram
|
|
232
|
+
)[0],
|
|
233
|
+
isSigner: false,
|
|
234
|
+
isWritable: true
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
// ext token account
|
|
238
|
+
pubkey: getAssociatedTokenAddressSync(
|
|
239
|
+
extMint,
|
|
240
|
+
payer,
|
|
241
|
+
true,
|
|
242
|
+
extTokenProgram
|
|
243
|
+
),
|
|
244
|
+
isSigner: false,
|
|
245
|
+
isWritable: true
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
// ext m vault
|
|
249
|
+
pubkey: getAssociatedTokenAddressSync(
|
|
250
|
+
this.programs.mMint,
|
|
251
|
+
PublicKey.findProgramAddressSync(
|
|
252
|
+
[Buffer.from("m_vault")],
|
|
253
|
+
extProgram
|
|
254
|
+
)[0],
|
|
255
|
+
true,
|
|
256
|
+
TOKEN_2022_PROGRAM_ID
|
|
257
|
+
),
|
|
258
|
+
isSigner: false,
|
|
259
|
+
isWritable: true
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
// ext m vault auth
|
|
263
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
264
|
+
[Buffer.from("m_vault")],
|
|
265
|
+
extProgram
|
|
266
|
+
)[0],
|
|
267
|
+
isSigner: false,
|
|
268
|
+
isWritable: false
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
// ext mint auth
|
|
272
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
273
|
+
[Buffer.from("mint_authority")],
|
|
274
|
+
extProgram
|
|
275
|
+
)[0],
|
|
276
|
+
isSigner: false,
|
|
277
|
+
isWritable: false
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
// ext program
|
|
281
|
+
pubkey: extProgram,
|
|
282
|
+
isSigner: false,
|
|
283
|
+
isWritable: false
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
// swap program
|
|
287
|
+
pubkey: this.programs.swap,
|
|
288
|
+
isSigner: false,
|
|
289
|
+
isWritable: false
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
// ext token program
|
|
293
|
+
pubkey: extTokenProgram,
|
|
294
|
+
isSigner: false,
|
|
295
|
+
isWritable: false
|
|
296
|
+
}
|
|
297
|
+
],
|
|
298
|
+
data: Buffer.concat([
|
|
299
|
+
Buffer.from(sha256("global:transfer_extension_burn").subarray(0, 8)),
|
|
300
|
+
new BN(amount2).toArrayLike(Buffer, "le", 8),
|
|
301
|
+
// amount
|
|
302
|
+
new BN(chainToChainId(recipient.chain)).toArrayLike(Buffer, "le", 2),
|
|
303
|
+
// chain_id
|
|
304
|
+
recipientAddress,
|
|
305
|
+
// recipient_address
|
|
306
|
+
destinationToken,
|
|
307
|
+
// destination_token
|
|
308
|
+
Buffer.from([Number(shouldQueue)])
|
|
309
|
+
// should_queue
|
|
310
|
+
])
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
getReleaseInboundMintExtensionIx(nttMessage, emitterChain, payer, extMint, extAta) {
|
|
314
|
+
const extension = this.extPrograms[extMint.toBase58()];
|
|
315
|
+
if (!extension) {
|
|
316
|
+
throw new Error(
|
|
317
|
+
`No extension program found for mint ${extMint.toBase58()}`
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
const { program: extProgram, tokenProgram: extTokenProgram } = extension;
|
|
321
|
+
return new TransactionInstruction({
|
|
322
|
+
programId: this.ntt.program.programId,
|
|
323
|
+
keys: [
|
|
324
|
+
{
|
|
325
|
+
pubkey: payer,
|
|
326
|
+
isSigner: true,
|
|
327
|
+
isWritable: true
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
// config
|
|
331
|
+
pubkey: this.ntt.pdas.configAccount(),
|
|
332
|
+
isSigner: false,
|
|
333
|
+
isWritable: false
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
// inbox item
|
|
337
|
+
pubkey: this.ntt.pdas.inboxItemAccount(emitterChain, nttMessage),
|
|
338
|
+
isSigner: false,
|
|
339
|
+
isWritable: true
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
// recipient (mint to token auth which wraps to user)
|
|
343
|
+
pubkey: getAssociatedTokenAddressSync(
|
|
344
|
+
this.ntt.config.mint,
|
|
345
|
+
PublicKey.findProgramAddressSync(
|
|
346
|
+
[Buffer.from("token_authority")],
|
|
347
|
+
this.ntt.program.programId
|
|
348
|
+
)[0],
|
|
349
|
+
true,
|
|
350
|
+
TOKEN_2022_PROGRAM_ID
|
|
351
|
+
),
|
|
352
|
+
isSigner: false,
|
|
353
|
+
isWritable: true
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
// token auth
|
|
357
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
358
|
+
[Buffer.from("token_authority")],
|
|
359
|
+
this.ntt.program.programId
|
|
360
|
+
)[0],
|
|
361
|
+
isSigner: false,
|
|
362
|
+
isWritable: false
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
// m mint
|
|
366
|
+
pubkey: this.ntt.config.mint,
|
|
367
|
+
isSigner: false,
|
|
368
|
+
isWritable: true
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
// m token program
|
|
372
|
+
pubkey: TOKEN_2022_PROGRAM_ID,
|
|
373
|
+
isSigner: false,
|
|
374
|
+
isWritable: false
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
// custody
|
|
378
|
+
pubkey: this.ntt.config.custody,
|
|
379
|
+
isSigner: false,
|
|
380
|
+
isWritable: true
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
// earn program
|
|
384
|
+
pubkey: this.programs.earn,
|
|
385
|
+
isSigner: false,
|
|
386
|
+
isWritable: false
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
// m global
|
|
390
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
391
|
+
[Buffer.from("global")],
|
|
392
|
+
this.programs.earn
|
|
393
|
+
)[0],
|
|
394
|
+
isSigner: false,
|
|
395
|
+
isWritable: false
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
// ext mint
|
|
399
|
+
pubkey: extMint,
|
|
400
|
+
isSigner: false,
|
|
401
|
+
isWritable: true
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
// swap global
|
|
405
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
406
|
+
[Buffer.from("global")],
|
|
407
|
+
this.programs.swap
|
|
408
|
+
)[0],
|
|
409
|
+
isSigner: false,
|
|
410
|
+
isWritable: false
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
// ext global
|
|
414
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
415
|
+
[Buffer.from("global")],
|
|
416
|
+
extProgram
|
|
417
|
+
)[0],
|
|
418
|
+
isSigner: false,
|
|
419
|
+
isWritable: true
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
// ext m vault auth
|
|
423
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
424
|
+
[Buffer.from("m_vault")],
|
|
425
|
+
extProgram
|
|
426
|
+
)[0],
|
|
427
|
+
isSigner: false,
|
|
428
|
+
isWritable: false
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
// ext mint auth
|
|
432
|
+
pubkey: PublicKey.findProgramAddressSync(
|
|
433
|
+
[Buffer.from("mint_authority")],
|
|
434
|
+
extProgram
|
|
435
|
+
)[0],
|
|
436
|
+
isSigner: false,
|
|
437
|
+
isWritable: false
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
// ext m vault
|
|
441
|
+
pubkey: getAssociatedTokenAddressSync(
|
|
442
|
+
this.ntt.config.mint,
|
|
443
|
+
PublicKey.findProgramAddressSync(
|
|
444
|
+
[Buffer.from("m_vault")],
|
|
445
|
+
extProgram
|
|
446
|
+
)[0],
|
|
447
|
+
true,
|
|
448
|
+
TOKEN_2022_PROGRAM_ID
|
|
449
|
+
),
|
|
450
|
+
isSigner: false,
|
|
451
|
+
isWritable: true
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
// ext token account
|
|
455
|
+
pubkey: extAta,
|
|
456
|
+
isSigner: false,
|
|
457
|
+
isWritable: true
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
// ext token account
|
|
461
|
+
pubkey: this.programs.swap,
|
|
462
|
+
isSigner: false,
|
|
463
|
+
isWritable: false
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
// ext program
|
|
467
|
+
pubkey: extProgram,
|
|
468
|
+
isSigner: false,
|
|
469
|
+
isWritable: false
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
// ext token program
|
|
473
|
+
pubkey: extTokenProgram,
|
|
474
|
+
isSigner: false,
|
|
475
|
+
isWritable: false
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
// system program
|
|
479
|
+
pubkey: SystemProgram.programId,
|
|
480
|
+
isSigner: false,
|
|
481
|
+
isWritable: false
|
|
482
|
+
}
|
|
483
|
+
],
|
|
484
|
+
data: Buffer.concat([
|
|
485
|
+
Buffer.from(
|
|
486
|
+
sha256("global:release_inbound_mint_extension").subarray(0, 8)
|
|
487
|
+
)
|
|
488
|
+
])
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
async getAddressLookupTableAccounts(connection) {
|
|
492
|
+
const info = await connection.getAccountInfo(this.programs.lut);
|
|
493
|
+
return new AddressLookupTableAccount({
|
|
494
|
+
key: this.programs.lut,
|
|
495
|
+
state: AddressLookupTableAccount.deserialize(info.data)
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
static async createReleaseInboundMintInstruction(ntt, args) {
|
|
499
|
+
const router = new _SolanaRoutes(ntt);
|
|
500
|
+
const { additionalPayload } = args.nttMessage.payload;
|
|
501
|
+
if (additionalPayload.length < 40) {
|
|
502
|
+
throw new Error(
|
|
503
|
+
`Invalid additionalPayload length: ${additionalPayload.length}, expected at least 40 bytes`
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
const destinationMint = new PublicKey(
|
|
507
|
+
// first 8 bytes is the index, next 32 bytes is the mint address
|
|
508
|
+
additionalPayload.slice(8, 40)
|
|
509
|
+
);
|
|
510
|
+
if (destinationMint.equals(ntt.config.mint)) {
|
|
511
|
+
return [
|
|
512
|
+
await NTT.createReleaseInboundMintInstruction(
|
|
513
|
+
ntt.program,
|
|
514
|
+
ntt.config,
|
|
515
|
+
args
|
|
516
|
+
)
|
|
517
|
+
];
|
|
518
|
+
}
|
|
519
|
+
const extPrograms = router.extPrograms[destinationMint.toBase58()];
|
|
520
|
+
if (!extPrograms) {
|
|
521
|
+
throw new Error(
|
|
522
|
+
`No extension program found for mint ${destinationMint.toBase58()}`
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
const extAta = getAssociatedTokenAddressSync(
|
|
526
|
+
destinationMint,
|
|
527
|
+
args.recipient,
|
|
528
|
+
true,
|
|
529
|
+
extPrograms.tokenProgram
|
|
530
|
+
);
|
|
531
|
+
const ixs = [];
|
|
532
|
+
const acctInfo = await ntt.connection.getAccountInfo(extAta);
|
|
533
|
+
if (acctInfo === null) {
|
|
534
|
+
ixs.push(
|
|
535
|
+
createAssociatedTokenAccountInstruction(
|
|
536
|
+
args.payer,
|
|
537
|
+
extAta,
|
|
538
|
+
args.recipient,
|
|
539
|
+
destinationMint,
|
|
540
|
+
extPrograms.tokenProgram
|
|
541
|
+
)
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
ixs.push(
|
|
545
|
+
router.getReleaseInboundMintExtensionIx(
|
|
546
|
+
args.nttMessage,
|
|
547
|
+
args.chain,
|
|
548
|
+
args.payer,
|
|
549
|
+
destinationMint,
|
|
550
|
+
extAta
|
|
551
|
+
)
|
|
552
|
+
);
|
|
553
|
+
return ixs;
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
function pk(address) {
|
|
557
|
+
return new PublicKey(address);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/m0AutomaticRoute.ts
|
|
561
|
+
var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
21
562
|
static supportedNetworks() {
|
|
22
563
|
return ["Mainnet", "Testnet"];
|
|
23
564
|
}
|
|
@@ -27,9 +568,15 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
27
568
|
static supportedChains(network) {
|
|
28
569
|
switch (network) {
|
|
29
570
|
case "Mainnet":
|
|
30
|
-
return ["Ethereum", "Arbitrum", "Optimism", "Solana"];
|
|
571
|
+
return ["Ethereum", "Arbitrum", "Optimism", "Solana", "Fogo"];
|
|
31
572
|
case "Testnet":
|
|
32
|
-
return [
|
|
573
|
+
return [
|
|
574
|
+
"Sepolia",
|
|
575
|
+
"ArbitrumSepolia",
|
|
576
|
+
"OptimismSepolia",
|
|
577
|
+
"Solana",
|
|
578
|
+
"Fogo"
|
|
579
|
+
];
|
|
33
580
|
default:
|
|
34
581
|
throw new Error(`Unsupported network: ${network}`);
|
|
35
582
|
}
|
|
@@ -49,7 +596,9 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
49
596
|
case "ArbitrumSepolia":
|
|
50
597
|
return this.EVM_CONTRACTS;
|
|
51
598
|
case "Solana":
|
|
52
|
-
return
|
|
599
|
+
return SolanaRoutes.getSolanaContracts(chainContext);
|
|
600
|
+
case "Fogo":
|
|
601
|
+
return SolanaRoutes.getSolanaContracts(chainContext);
|
|
53
602
|
default:
|
|
54
603
|
throw new Error(`Unsupported chain: ${chainContext.chain}`);
|
|
55
604
|
}
|
|
@@ -67,8 +616,9 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
67
616
|
return [];
|
|
68
617
|
}
|
|
69
618
|
const { token: mToken, mLikeTokens } = this.getContracts(toChain);
|
|
70
|
-
|
|
71
|
-
|
|
619
|
+
return [mToken, ...mLikeTokens].map(
|
|
620
|
+
(x) => Wormhole.tokenId(toChain.chain, x)
|
|
621
|
+
);
|
|
72
622
|
}
|
|
73
623
|
static isProtocolSupported(chain) {
|
|
74
624
|
return chain.supportsProtocol("Ntt");
|
|
@@ -163,14 +713,38 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
163
713
|
const platform = chainToPlatform(fromChain.chain);
|
|
164
714
|
const transferAmount = amount.units(params.normalizedParams.amount);
|
|
165
715
|
const options = params.normalizedParams.options;
|
|
166
|
-
if (platform
|
|
716
|
+
if (!_M0AutomaticRoute.isPlatformSupported(platform))
|
|
167
717
|
throw new Error(`Unsupported platform ${platform}`);
|
|
168
718
|
const ntt = await fromChain.getProtocol("Ntt", {
|
|
169
719
|
ntt: _M0AutomaticRoute.getContracts(fromChain)
|
|
170
720
|
});
|
|
171
721
|
const sourceToken = canonicalAddress(request.source.id);
|
|
172
722
|
const destinationToken = canonicalAddress(request.destination.id);
|
|
173
|
-
const initXfer = platform === "Evm" ?
|
|
723
|
+
const initXfer = platform === "Evm" ? (
|
|
724
|
+
// for EVM call transferMLike function
|
|
725
|
+
this.transferMLike(
|
|
726
|
+
ntt,
|
|
727
|
+
// @ts-ignore
|
|
728
|
+
sender,
|
|
729
|
+
transferAmount,
|
|
730
|
+
to,
|
|
731
|
+
sourceToken,
|
|
732
|
+
destinationToken,
|
|
733
|
+
options
|
|
734
|
+
)
|
|
735
|
+
) : (
|
|
736
|
+
// for Solana use custom transfer instruction
|
|
737
|
+
this.transferSolanaExtension(
|
|
738
|
+
ntt,
|
|
739
|
+
// @ts-ignore
|
|
740
|
+
sender,
|
|
741
|
+
transferAmount,
|
|
742
|
+
to,
|
|
743
|
+
sourceToken,
|
|
744
|
+
destinationToken,
|
|
745
|
+
options
|
|
746
|
+
)
|
|
747
|
+
);
|
|
174
748
|
const txids = await signSendWait(fromChain, initXfer, signer);
|
|
175
749
|
return {
|
|
176
750
|
from: fromChain.chain,
|
|
@@ -230,6 +804,75 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
230
804
|
parallelizable
|
|
231
805
|
);
|
|
232
806
|
}
|
|
807
|
+
async *transferSolanaExtension(ntt, sender, amount2, recipient, sourceToken, destinationToken, options) {
|
|
808
|
+
const router = new SolanaRoutes(ntt);
|
|
809
|
+
if ((await ntt.getConfig()).mint.toBase58() === sourceToken) {
|
|
810
|
+
return ntt.transfer(sender, amount2, recipient, options);
|
|
811
|
+
}
|
|
812
|
+
const config = await ntt.getConfig();
|
|
813
|
+
if (config.paused) throw new Error("Contract is paused");
|
|
814
|
+
const outboxItem = Keypair.generate();
|
|
815
|
+
const payerAddress = new SolanaAddress(sender).unwrap();
|
|
816
|
+
const ixs = [
|
|
817
|
+
router.getTransferExtensionBurnIx(
|
|
818
|
+
amount2,
|
|
819
|
+
recipient,
|
|
820
|
+
new PublicKey(sender.toUint8Array()),
|
|
821
|
+
outboxItem.publicKey,
|
|
822
|
+
new PublicKey(sourceToken),
|
|
823
|
+
toUniversal(recipient.chain, destinationToken).toUint8Array(),
|
|
824
|
+
options.queue
|
|
825
|
+
)
|
|
826
|
+
];
|
|
827
|
+
for (let ix = 0; ix < ntt.transceivers.length; ++ix) {
|
|
828
|
+
if (ix === 0) {
|
|
829
|
+
const whTransceiver = await ntt.getWormholeTransceiver();
|
|
830
|
+
if (!whTransceiver) {
|
|
831
|
+
throw new Error("wormhole transceiver not found");
|
|
832
|
+
}
|
|
833
|
+
const releaseIx = await whTransceiver.createReleaseWormholeOutboundIx(
|
|
834
|
+
payerAddress,
|
|
835
|
+
outboxItem.publicKey,
|
|
836
|
+
!options.queue
|
|
837
|
+
);
|
|
838
|
+
ixs.push(releaseIx);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
const tx = new Transaction();
|
|
842
|
+
tx.feePayer = payerAddress;
|
|
843
|
+
tx.add(...ixs);
|
|
844
|
+
if (options.automatic) {
|
|
845
|
+
if (!ntt.quoter)
|
|
846
|
+
throw new Error(
|
|
847
|
+
"No quoter available, cannot initiate an automatic transfer."
|
|
848
|
+
);
|
|
849
|
+
const fee = await ntt.quoteDeliveryPrice(recipient.chain, options);
|
|
850
|
+
const relayIx = await ntt.quoter.createRequestRelayInstruction(
|
|
851
|
+
payerAddress,
|
|
852
|
+
outboxItem.publicKey,
|
|
853
|
+
recipient.chain,
|
|
854
|
+
Number(fee) / LAMPORTS_PER_SOL,
|
|
855
|
+
Number(options.gasDropoff ?? 0n) / WEI_PER_GWEI
|
|
856
|
+
);
|
|
857
|
+
tx.add(relayIx);
|
|
858
|
+
}
|
|
859
|
+
const luts = [];
|
|
860
|
+
try {
|
|
861
|
+
luts.push(await ntt.getAddressLookupTable());
|
|
862
|
+
luts.push(await router.getAddressLookupTableAccounts(ntt.connection));
|
|
863
|
+
} catch {
|
|
864
|
+
}
|
|
865
|
+
const messageV0 = new TransactionMessage({
|
|
866
|
+
payerKey: payerAddress,
|
|
867
|
+
instructions: tx.instructions,
|
|
868
|
+
recentBlockhash: (await ntt.connection.getLatestBlockhash()).blockhash
|
|
869
|
+
}).compileToV0Message(luts);
|
|
870
|
+
const vtx = new VersionedTransaction(messageV0);
|
|
871
|
+
yield ntt.createUnsignedTx(
|
|
872
|
+
{ transaction: vtx, signers: [outboxItem] },
|
|
873
|
+
"Ntt.Transfer"
|
|
874
|
+
);
|
|
875
|
+
}
|
|
233
876
|
async *track(receipt, timeout) {
|
|
234
877
|
const isEvmPlatform = (chain) => chainToPlatform(chain) === "Evm";
|
|
235
878
|
if (isSourceInitiated(receipt) || isSourceFinalized(receipt)) {
|
|
@@ -272,7 +915,9 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
272
915
|
}
|
|
273
916
|
}
|
|
274
917
|
if (isRedeemed(receipt)) {
|
|
275
|
-
const {
|
|
918
|
+
const {
|
|
919
|
+
attestation: { attestation: vaa }
|
|
920
|
+
} = receipt;
|
|
276
921
|
const payload = vaa.payloadName === "WormholeTransfer" ? vaa.payload : vaa.payload["payload"];
|
|
277
922
|
const isExecuted = isEvmPlatform(receipt.to) ? await ntt.manager.isMessageExecuted(
|
|
278
923
|
Ntt.messageDigest(vaa.emitterChain, payload["nttManagerPayload"])
|
|
@@ -292,8 +937,6 @@ var _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
|
|
|
292
937
|
_M0AutomaticRoute.NATIVE_GAS_DROPOFF_SUPPORTED = false;
|
|
293
938
|
// Wrapped M token address is the same on EVM chains
|
|
294
939
|
_M0AutomaticRoute.EVM_WRAPPED_M_TOKEN = "0x437cc33344a0B27A429f795ff6B469C72698B291";
|
|
295
|
-
_M0AutomaticRoute.SOLANA_MAINNET_M_TOKEN = "mzerokyEX9TNDoK4o2YZQBDmMzjokAeN6M2g2S3pLJo";
|
|
296
|
-
_M0AutomaticRoute.SOLANA_TESTNET_M_TOKEN = "mzeroZRGCah3j5xEWp2Nih3GDejSBbH1rbHoxDg8By6";
|
|
297
940
|
// Contract addresses are the same on all EVM chains
|
|
298
941
|
_M0AutomaticRoute.EVM_CONTRACTS = {
|
|
299
942
|
// M token address is the same on EVM chains
|
|
@@ -308,4 +951,4 @@ _M0AutomaticRoute.EVM_CONTRACTS = {
|
|
|
308
951
|
_M0AutomaticRoute.meta = { name: "M0AutomaticRoute", provider: "M0" };
|
|
309
952
|
var M0AutomaticRoute = _M0AutomaticRoute;
|
|
310
953
|
|
|
311
|
-
export { M0AutomaticRoute };
|
|
954
|
+
export { M0AutomaticRoute, SolanaRoutes };
|