@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.mjs CHANGED
@@ -1,23 +1,564 @@
1
- import { routes, Wormhole, isSameToken, chainToPlatform, amount, finality, canonicalAddress, signSendWait, TransferState, universalAddress, toChainId, toUniversal, isSourceInitiated, isSourceFinalized, isAttested, isRedeemed } from '@wormhole-foundation/sdk-connect';
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 _M0AutomaticRoute = class _M0AutomaticRoute extends routes.AutomaticRoute {
11
- static solanaContracts(network) {
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: network == "Mainnet" ? this.SOLANA_MAINNET_M_TOKEN : this.SOLANA_TESTNET_M_TOKEN,
14
- // Only M token can be bridged from Solana
15
- mLikeTokens: [],
16
- manager: "mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY",
17
- transceiver: { wormhole: "mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY" },
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 ["Sepolia", "ArbitrumSepolia", "OptimismSepolia", "Solana"];
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 this.solanaContracts(chainContext.network);
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
- const toMToken = Wormhole.tokenId(toChain.chain, mToken);
71
- return chainToPlatform(fromChain.chain) === "Solana" ? [toMToken] : [toMToken, ...mLikeTokens.map((x) => Wormhole.tokenId(toChain.chain, x))];
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 !== "Evm" && platform !== "Solana")
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" ? this.transferMLike(ntt, sender, transferAmount, to, sourceToken, destinationToken, options) : ntt.transfer(sender, transferAmount, to, options);
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 { attestation: { attestation: vaa } } = receipt;
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 };