@fogo/sessions-sdk 0.0.19 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/index.d.ts +16 -0
- package/cjs/index.js +103 -32
- package/esm/index.d.ts +16 -0
- package/esm/index.js +101 -32
- package/package.json +2 -2
package/cjs/index.d.ts
CHANGED
|
@@ -1310,6 +1310,20 @@ export type Session = {
|
|
|
1310
1310
|
sendTransaction: (instructions: Parameters<SessionContext["sendTransaction"]>[1]) => Promise<TransactionResult>;
|
|
1311
1311
|
sessionInfo: NonNullable<z.infer<typeof sessionInfoSchema>>;
|
|
1312
1312
|
};
|
|
1313
|
+
export declare const getTransferFee: (context: SessionContext) => Promise<{
|
|
1314
|
+
fee: bigint;
|
|
1315
|
+
metadata: import("@metaplex-foundation/umi").PublicKey<string>;
|
|
1316
|
+
mint: PublicKey;
|
|
1317
|
+
symbolOrMint: string;
|
|
1318
|
+
decimals: number;
|
|
1319
|
+
}>;
|
|
1320
|
+
export declare const getBridgeOutFee: (context: SessionContext) => Promise<{
|
|
1321
|
+
fee: bigint;
|
|
1322
|
+
metadata: import("@metaplex-foundation/umi").PublicKey<string>;
|
|
1323
|
+
mint: PublicKey;
|
|
1324
|
+
symbolOrMint: string;
|
|
1325
|
+
decimals: number;
|
|
1326
|
+
}>;
|
|
1313
1327
|
type SendTransferOptions = {
|
|
1314
1328
|
context: SessionContext;
|
|
1315
1329
|
walletPublicKey: PublicKey;
|
|
@@ -1317,6 +1331,7 @@ type SendTransferOptions = {
|
|
|
1317
1331
|
mint: PublicKey;
|
|
1318
1332
|
amount: bigint;
|
|
1319
1333
|
recipient: PublicKey;
|
|
1334
|
+
feeConfig: Awaited<ReturnType<typeof getTransferFee>>;
|
|
1320
1335
|
};
|
|
1321
1336
|
export declare const sendTransfer: (options: SendTransferOptions) => Promise<TransactionResult>;
|
|
1322
1337
|
type SendBridgeOutOptions = {
|
|
@@ -1332,6 +1347,7 @@ type SendBridgeOutOptions = {
|
|
|
1332
1347
|
toToken: WormholeToken & {
|
|
1333
1348
|
chain: "Solana";
|
|
1334
1349
|
};
|
|
1350
|
+
feeConfig: Awaited<ReturnType<typeof getBridgeOutFee>>;
|
|
1335
1351
|
};
|
|
1336
1352
|
type WormholeToken = {
|
|
1337
1353
|
chain: Chain;
|
package/cjs/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.verifyLogInToken = exports.createLogInToken = exports.bridgeIn = exports.bridgeOut = exports.sendTransfer = exports.SessionResultType = exports.getDomainRecordAddress = exports.AuthorizedTokens = exports.AuthorizedProgramsType = exports.getSessionAccount = exports.reestablishSession = exports.revokeSession = exports.replaceSession = exports.establishSession = exports.createSessionConnection = exports.TransactionResultType = exports.Network = exports.createSessionContext = void 0;
|
|
6
|
+
exports.verifyLogInToken = exports.createLogInToken = exports.bridgeIn = exports.bridgeOut = exports.sendTransfer = exports.getBridgeOutFee = exports.getTransferFee = exports.SessionResultType = exports.getDomainRecordAddress = exports.AuthorizedTokens = exports.AuthorizedProgramsType = exports.getSessionAccount = exports.reestablishSession = exports.revokeSession = exports.replaceSession = exports.establishSession = exports.createSessionConnection = exports.TransactionResultType = exports.Network = exports.createSessionContext = void 0;
|
|
7
7
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
8
8
|
const sessions_idls_1 = require("@fogo/sessions-idls");
|
|
9
9
|
const mpl_token_metadata_1 = require("@metaplex-foundation/mpl-token-metadata");
|
|
@@ -39,9 +39,9 @@ const TOKENLESS_PERMISSIONS_VALUE = "this app may not spend any tokens";
|
|
|
39
39
|
const CURRENT_MAJOR = "0";
|
|
40
40
|
const CURRENT_MINOR = "3";
|
|
41
41
|
const CURRENT_INTENT_TRANSFER_MAJOR = "0";
|
|
42
|
-
const CURRENT_INTENT_TRANSFER_MINOR = "
|
|
42
|
+
const CURRENT_INTENT_TRANSFER_MINOR = "2";
|
|
43
43
|
const CURRENT_BRIDGE_OUT_MAJOR = "0";
|
|
44
|
-
const CURRENT_BRIDGE_OUT_MINOR = "
|
|
44
|
+
const CURRENT_BRIDGE_OUT_MINOR = "2";
|
|
45
45
|
const SESSION_ESTABLISHMENT_LOOKUP_TABLE_ADDRESS = {
|
|
46
46
|
[connection_js_1.Network.Testnet]: "B8cUjJMqaWWTNNSTXBmeptjWswwCH1gTSCRYv4nu7kJW",
|
|
47
47
|
[connection_js_1.Network.Mainnet]: undefined,
|
|
@@ -446,7 +446,10 @@ const BRIDGING_ADDRESS_LOOKUP_TABLE = {
|
|
|
446
446
|
// USDC
|
|
447
447
|
ELNbJ1RtERV2fjtuZjbTscDekWhVzkQ1LjmiPsxp5uND: "4FCi6LptexBdZtaePsoCMeb1XpCijxnWu96g5LsSb6WP",
|
|
448
448
|
},
|
|
449
|
-
[connection_js_1.Network.Mainnet]:
|
|
449
|
+
[connection_js_1.Network.Mainnet]: {
|
|
450
|
+
// USDC
|
|
451
|
+
uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG: "84k3mfNjmyinpZwyev7F15ChEW3Kqa3NoUkCJXXs4qkw",
|
|
452
|
+
},
|
|
450
453
|
};
|
|
451
454
|
const buildStartSessionInstruction = async (options, sessionKey, tokens) => {
|
|
452
455
|
const instruction = new sessions_idls_1.SessionManagerProgram(new anchor_1.AnchorProvider(options.context.connection, {}, {})).methods
|
|
@@ -499,12 +502,52 @@ const EstablishSessionResult = {
|
|
|
499
502
|
error,
|
|
500
503
|
}),
|
|
501
504
|
};
|
|
505
|
+
const USDC_MINT = {
|
|
506
|
+
[connection_js_1.Network.Mainnet]: "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
|
|
507
|
+
[connection_js_1.Network.Testnet]: "ELNbJ1RtERV2fjtuZjbTscDekWhVzkQ1LjmiPsxp5uND",
|
|
508
|
+
};
|
|
509
|
+
const USDC_DECIMALS = 6;
|
|
510
|
+
const getTransferFee = async (context) => {
|
|
511
|
+
const { fee, ...config } = await getFee(context);
|
|
512
|
+
return {
|
|
513
|
+
...config,
|
|
514
|
+
fee: fee.intrachainTransfer,
|
|
515
|
+
};
|
|
516
|
+
};
|
|
517
|
+
exports.getTransferFee = getTransferFee;
|
|
518
|
+
const getBridgeOutFee = async (context) => {
|
|
519
|
+
const { fee, ...config } = await getFee(context);
|
|
520
|
+
return {
|
|
521
|
+
...config,
|
|
522
|
+
fee: fee.bridgeTransfer,
|
|
523
|
+
};
|
|
524
|
+
};
|
|
525
|
+
exports.getBridgeOutFee = getBridgeOutFee;
|
|
526
|
+
const getFee = async (context) => {
|
|
527
|
+
const program = new sessions_idls_1.IntentTransferProgram(new anchor_1.AnchorProvider(context.connection, {}, {}));
|
|
528
|
+
const umi = (0, umi_bundle_defaults_1.createUmi)(context.connection.rpcEndpoint);
|
|
529
|
+
const usdcMintAddress = USDC_MINT[context.network];
|
|
530
|
+
const usdcMint = new web3_js_1.PublicKey(usdcMintAddress);
|
|
531
|
+
const [feeConfigPda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("fee_config"), usdcMint.toBytes()], program.programId);
|
|
532
|
+
const feeConfig = await program.account.feeConfig.fetch(feeConfigPda);
|
|
533
|
+
return {
|
|
534
|
+
metadata: (0, mpl_token_metadata_1.findMetadataPda)(umi, {
|
|
535
|
+
mint: (0, umi_1.publicKey)(usdcMintAddress),
|
|
536
|
+
})[0],
|
|
537
|
+
mint: usdcMint,
|
|
538
|
+
symbolOrMint: context.network === connection_js_1.Network.Mainnet ? "USDC.s" : "USDC",
|
|
539
|
+
decimals: USDC_DECIMALS,
|
|
540
|
+
fee: {
|
|
541
|
+
intrachainTransfer: BigInt(feeConfig.intrachainTransferFee.toString()),
|
|
542
|
+
bridgeTransfer: BigInt(feeConfig.bridgeTransferFee.toString()),
|
|
543
|
+
},
|
|
544
|
+
};
|
|
545
|
+
};
|
|
502
546
|
const TRANSFER_MESSAGE_HEADER = `Fogo Transfer:
|
|
503
547
|
Signing this intent will transfer the tokens as described below.
|
|
504
548
|
`;
|
|
505
549
|
const sendTransfer = async (options) => {
|
|
506
550
|
const sourceAta = (0, spl_token_1.getAssociatedTokenAddressSync)(options.mint, options.walletPublicKey);
|
|
507
|
-
const destinationAta = (0, spl_token_1.getAssociatedTokenAddressSync)(options.mint, options.recipient);
|
|
508
551
|
const program = new sessions_idls_1.IntentTransferProgram(new anchor_1.AnchorProvider(options.context.connection, {}, {}));
|
|
509
552
|
const umi = (0, umi_bundle_defaults_1.createUmi)(options.context.connection.rpcEndpoint);
|
|
510
553
|
const metaplexMint = (0, umi_1.publicKey)(options.mint.toBase58());
|
|
@@ -512,12 +555,14 @@ const sendTransfer = async (options) => {
|
|
|
512
555
|
const metadata = await (0, mpl_token_metadata_1.safeFetchMetadata)(umi, metadataAddress);
|
|
513
556
|
const symbol = metadata?.symbol ?? undefined;
|
|
514
557
|
return options.context.sendTransaction(undefined, [
|
|
515
|
-
(
|
|
516
|
-
await buildTransferIntentInstruction(program, options, symbol),
|
|
558
|
+
await buildTransferIntentInstruction(program, options, symbol, options.feeConfig.symbolOrMint, amountToString(options.feeConfig.fee, options.feeConfig.decimals)),
|
|
517
559
|
await program.methods
|
|
518
560
|
.sendTokens()
|
|
519
561
|
.accounts({
|
|
520
|
-
|
|
562
|
+
destinationOwner: options.recipient,
|
|
563
|
+
feeMetadata: options.feeConfig.metadata,
|
|
564
|
+
feeMint: options.feeConfig.mint,
|
|
565
|
+
feeSource: (0, spl_token_1.getAssociatedTokenAddressSync)(options.feeConfig.mint, options.walletPublicKey),
|
|
521
566
|
mint: options.mint,
|
|
522
567
|
source: sourceAta,
|
|
523
568
|
sponsor: options.context.payer,
|
|
@@ -528,7 +573,7 @@ const sendTransfer = async (options) => {
|
|
|
528
573
|
]);
|
|
529
574
|
};
|
|
530
575
|
exports.sendTransfer = sendTransfer;
|
|
531
|
-
const buildTransferIntentInstruction = async (program, options, symbol) => {
|
|
576
|
+
const buildTransferIntentInstruction = async (program, options, symbol, feeToken, feeAmount) => {
|
|
532
577
|
const [nonce, { decimals }] = await Promise.all([
|
|
533
578
|
getNonce(program, options.walletPublicKey, NonceType.Transfer),
|
|
534
579
|
(0, spl_token_1.getMint)(options.context.connection, options.mint),
|
|
@@ -541,6 +586,8 @@ const buildTransferIntentInstruction = async (program, options, symbol) => {
|
|
|
541
586
|
token: symbol ?? options.mint.toBase58(),
|
|
542
587
|
amount: amountToString(options.amount, decimals),
|
|
543
588
|
recipient: options.recipient.toBase58(),
|
|
589
|
+
fee_token: feeToken,
|
|
590
|
+
fee_amount: feeAmount,
|
|
544
591
|
nonce: nonce === null ? "1" : nonce.nonce.add(new bn_js_1.default(1)).toString(),
|
|
545
592
|
}),
|
|
546
593
|
].join("\n"));
|
|
@@ -554,6 +601,7 @@ const buildTransferIntentInstruction = async (program, options, symbol) => {
|
|
|
554
601
|
const BRIDGE_OUT_MESSAGE_HEADER = `Fogo Bridge Transfer:
|
|
555
602
|
Signing this intent will bridge out the tokens as described below.
|
|
556
603
|
`;
|
|
604
|
+
const BRIDGE_OUT_CUS = 220_000;
|
|
557
605
|
const bridgeOut = async (options) => {
|
|
558
606
|
const { wh, route, transferRequest, transferParams, decimals } = await buildWormholeTransfer(options, options.context.connection);
|
|
559
607
|
// @ts-expect-error the wormhole client types are incorrect and do not
|
|
@@ -564,35 +612,47 @@ const bridgeOut = async (options) => {
|
|
|
564
612
|
const metaplexMint = (0, umi_1.publicKey)(options.fromToken.mint.toBase58());
|
|
565
613
|
const metadataAddress = (0, mpl_token_metadata_1.findMetadataPda)(umi, { mint: metaplexMint })[0];
|
|
566
614
|
const outboxItem = web3_js_1.Keypair.generate();
|
|
567
|
-
const [metadata, nttPdas] = await Promise.all([
|
|
615
|
+
const [metadata, nttPdas, destinationAtaExists] = await Promise.all([
|
|
568
616
|
(0, mpl_token_metadata_1.safeFetchMetadata)(umi, metadataAddress),
|
|
569
617
|
getNttPdas(options, wh, program, outboxItem.publicKey, new web3_js_1.PublicKey(quote.payeeAddress)),
|
|
618
|
+
getDestinationAtaExists(options.context, options.toToken.mint, options.walletPublicKey),
|
|
619
|
+
]);
|
|
620
|
+
const instructions = await Promise.all([
|
|
621
|
+
buildBridgeOutIntent(program, options, decimals, metadata?.symbol, options.feeConfig.symbolOrMint, amountToString(options.feeConfig.fee, options.feeConfig.decimals)),
|
|
622
|
+
program.methods
|
|
623
|
+
.bridgeNttTokens({
|
|
624
|
+
payDestinationAtaRent: !destinationAtaExists,
|
|
625
|
+
signedQuoteBytes: Buffer.from(quote.signedQuote),
|
|
626
|
+
})
|
|
627
|
+
.accounts({
|
|
628
|
+
sponsor: options.context.payer,
|
|
629
|
+
mint: options.fromToken.mint,
|
|
630
|
+
metadata: metadata?.symbol === undefined
|
|
631
|
+
? // eslint-disable-next-line unicorn/no-null
|
|
632
|
+
null
|
|
633
|
+
: new web3_js_1.PublicKey(metadataAddress),
|
|
634
|
+
source: (0, spl_token_1.getAssociatedTokenAddressSync)(options.fromToken.mint, options.walletPublicKey),
|
|
635
|
+
ntt: nttPdas,
|
|
636
|
+
feeMetadata: options.feeConfig.metadata,
|
|
637
|
+
feeMint: options.feeConfig.mint,
|
|
638
|
+
feeSource: (0, spl_token_1.getAssociatedTokenAddressSync)(options.feeConfig.mint, options.walletPublicKey),
|
|
639
|
+
})
|
|
640
|
+
.instruction(),
|
|
570
641
|
]);
|
|
571
|
-
const bridgeInstruction = await program.methods
|
|
572
|
-
.bridgeNttTokens({
|
|
573
|
-
execAmount: new bn_js_1.default(quote.estimatedCost.toString()),
|
|
574
|
-
relayInstructions: Buffer.from(quote.relayInstructions),
|
|
575
|
-
signedQuoteBytes: Buffer.from(quote.signedQuote),
|
|
576
|
-
})
|
|
577
|
-
.accounts({
|
|
578
|
-
sponsor: options.context.payer,
|
|
579
|
-
mint: options.fromToken.mint,
|
|
580
|
-
metadata:
|
|
581
|
-
// eslint-disable-next-line unicorn/no-null
|
|
582
|
-
metadata?.symbol === undefined ? null : new web3_js_1.PublicKey(metadataAddress),
|
|
583
|
-
source: (0, spl_token_1.getAssociatedTokenAddressSync)(options.fromToken.mint, options.walletPublicKey),
|
|
584
|
-
ntt: nttPdas,
|
|
585
|
-
})
|
|
586
|
-
.instruction();
|
|
587
642
|
return options.context.sendTransaction(options.sessionKey, [
|
|
588
|
-
|
|
589
|
-
|
|
643
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: BRIDGE_OUT_CUS }),
|
|
644
|
+
...instructions,
|
|
590
645
|
], {
|
|
591
646
|
extraSigners: [outboxItem],
|
|
592
647
|
addressLookupTable: BRIDGING_ADDRESS_LOOKUP_TABLE[options.context.network]?.[options.fromToken.mint.toBase58()],
|
|
593
648
|
});
|
|
594
649
|
};
|
|
595
650
|
exports.bridgeOut = bridgeOut;
|
|
651
|
+
const getDestinationAtaExists = async (context, token, wallet) => {
|
|
652
|
+
const solanaConnection = await context.getSolanaConnection();
|
|
653
|
+
const ataAccount = await solanaConnection.getAccountInfo((0, spl_token_1.getAssociatedTokenAddressSync)(token, wallet));
|
|
654
|
+
return ataAccount !== null;
|
|
655
|
+
};
|
|
596
656
|
// Here we use the Wormhole SDKs to produce the wormhole pdas that are needed
|
|
597
657
|
// for the bridge out transaction. Currently this is using wormhole SDK apis
|
|
598
658
|
// that are _technically_ public but it seems likely these are not considered to
|
|
@@ -610,6 +670,10 @@ const getNttPdas = async (options, wh, program, outboxItemPublicKey, quotePayeeA
|
|
|
610
670
|
const transceiverPdas = sdk_solana_ntt_1.NTT.transceiverPdas(options.fromToken.manager);
|
|
611
671
|
const [intentTransferSetterPda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("intent_transfer")], program.programId);
|
|
612
672
|
const wormholePdas = sdk_solana_core_1.utils.getWormholeDerivedAccounts(options.fromToken.manager, coreBridgeContract);
|
|
673
|
+
const [registeredTransceiverPda] = web3_js_1.PublicKey.findProgramAddressSync([
|
|
674
|
+
Buffer.from("registered_transceiver"),
|
|
675
|
+
options.fromToken.manager.toBytes(),
|
|
676
|
+
], options.fromToken.manager);
|
|
613
677
|
return {
|
|
614
678
|
emitter: transceiverPdas.emitterAccount(),
|
|
615
679
|
nttConfig: pdas.configAccount(),
|
|
@@ -622,14 +686,15 @@ const getNttPdas = async (options, wh, program, outboxItemPublicKey, quotePayeeA
|
|
|
622
686
|
nttSessionAuthority: pdas.sessionAuthority(intentTransferSetterPda, sdk_solana_ntt_1.NTT.transferArgs(options.amount, sdk_1.Wormhole.chainAddress("Solana", options.walletPublicKey.toBase58()), false)),
|
|
623
687
|
nttTokenAuthority: pdas.tokenAuthority(),
|
|
624
688
|
payeeNttWithExecutor: quotePayeeAddress,
|
|
625
|
-
transceiver:
|
|
689
|
+
transceiver: registeredTransceiverPda,
|
|
690
|
+
wormholeProgram: coreBridgeContract,
|
|
626
691
|
wormholeBridge: wormholePdas.wormholeBridge,
|
|
627
692
|
wormholeFeeCollector: wormholePdas.wormholeFeeCollector,
|
|
628
693
|
wormholeMessage: transceiverPdas.wormholeMessageAccount(outboxItemPublicKey),
|
|
629
694
|
wormholeSequence: wormholePdas.wormholeSequence,
|
|
630
695
|
};
|
|
631
696
|
};
|
|
632
|
-
const buildBridgeOutIntent = async (program, options, decimals, symbol) => {
|
|
697
|
+
const buildBridgeOutIntent = async (program, options, decimals, symbol, feeToken, feeAmount) => {
|
|
633
698
|
const nonce = await getNonce(program, options.walletPublicKey, NonceType.Bridge);
|
|
634
699
|
const message = new TextEncoder().encode([
|
|
635
700
|
BRIDGE_OUT_MESSAGE_HEADER,
|
|
@@ -640,6 +705,8 @@ const buildBridgeOutIntent = async (program, options, decimals, symbol) => {
|
|
|
640
705
|
token: symbol ?? options.fromToken.mint.toBase58(),
|
|
641
706
|
amount: amountToString(options.amount, decimals),
|
|
642
707
|
recipient_address: options.walletPublicKey.toBase58(),
|
|
708
|
+
fee_token: feeToken,
|
|
709
|
+
fee_amount: feeAmount,
|
|
643
710
|
nonce: nonce === null ? "1" : nonce.nonce.add(new bn_js_1.default(1)).toString(),
|
|
644
711
|
}),
|
|
645
712
|
].join("\n"));
|
|
@@ -665,7 +732,7 @@ const bridgeIn = async (options) => {
|
|
|
665
732
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
666
733
|
transaction.transaction, solanaConnection,
|
|
667
734
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
668
|
-
{ signers: transaction.signers
|
|
735
|
+
{ signers: transaction.signers }))),
|
|
669
736
|
}, quote, sdk_1.Wormhole.chainAddress("Fogo", options.walletPublicKey.toBase58())));
|
|
670
737
|
}
|
|
671
738
|
else {
|
|
@@ -674,8 +741,11 @@ const bridgeIn = async (options) => {
|
|
|
674
741
|
};
|
|
675
742
|
exports.bridgeIn = bridgeIn;
|
|
676
743
|
const buildWormholeTransfer = async (options, connection) => {
|
|
744
|
+
const solanaConnection = await options.context.getSolanaConnection();
|
|
677
745
|
const [wh, { decimals }] = await Promise.all([
|
|
678
|
-
(0, sdk_1.wormhole)(NETWORK_TO_WORMHOLE_NETWORK[options.context.network], [solana_1.default]
|
|
746
|
+
(0, sdk_1.wormhole)(NETWORK_TO_WORMHOLE_NETWORK[options.context.network], [solana_1.default], {
|
|
747
|
+
chains: { Solana: { rpc: solanaConnection.rpcEndpoint } },
|
|
748
|
+
}),
|
|
679
749
|
(0, spl_token_1.getMint)(connection, options.fromToken.mint),
|
|
680
750
|
]);
|
|
681
751
|
const Route = (0, sdk_route_ntt_1.nttExecutorRoute)({
|
|
@@ -710,6 +780,7 @@ const buildWormholeTransfer = async (options, connection) => {
|
|
|
710
780
|
});
|
|
711
781
|
const route = new Route(wh);
|
|
712
782
|
const transferRequest = await sdk_1.routes.RouteTransferRequest.create(wh, {
|
|
783
|
+
recipient: sdk_1.Wormhole.chainAddress(options.toToken.chain, options.walletPublicKey.toBase58()),
|
|
713
784
|
source: sdk_1.Wormhole.tokenId(options.fromToken.chain, options.fromToken.mint.toBase58()),
|
|
714
785
|
destination: sdk_1.Wormhole.tokenId(options.toToken.chain, options.toToken.mint.toBase58()),
|
|
715
786
|
});
|
package/esm/index.d.ts
CHANGED
|
@@ -1310,6 +1310,20 @@ export type Session = {
|
|
|
1310
1310
|
sendTransaction: (instructions: Parameters<SessionContext["sendTransaction"]>[1]) => Promise<TransactionResult>;
|
|
1311
1311
|
sessionInfo: NonNullable<z.infer<typeof sessionInfoSchema>>;
|
|
1312
1312
|
};
|
|
1313
|
+
export declare const getTransferFee: (context: SessionContext) => Promise<{
|
|
1314
|
+
fee: bigint;
|
|
1315
|
+
metadata: import("@metaplex-foundation/umi").PublicKey<string>;
|
|
1316
|
+
mint: PublicKey;
|
|
1317
|
+
symbolOrMint: string;
|
|
1318
|
+
decimals: number;
|
|
1319
|
+
}>;
|
|
1320
|
+
export declare const getBridgeOutFee: (context: SessionContext) => Promise<{
|
|
1321
|
+
fee: bigint;
|
|
1322
|
+
metadata: import("@metaplex-foundation/umi").PublicKey<string>;
|
|
1323
|
+
mint: PublicKey;
|
|
1324
|
+
symbolOrMint: string;
|
|
1325
|
+
decimals: number;
|
|
1326
|
+
}>;
|
|
1313
1327
|
type SendTransferOptions = {
|
|
1314
1328
|
context: SessionContext;
|
|
1315
1329
|
walletPublicKey: PublicKey;
|
|
@@ -1317,6 +1331,7 @@ type SendTransferOptions = {
|
|
|
1317
1331
|
mint: PublicKey;
|
|
1318
1332
|
amount: bigint;
|
|
1319
1333
|
recipient: PublicKey;
|
|
1334
|
+
feeConfig: Awaited<ReturnType<typeof getTransferFee>>;
|
|
1320
1335
|
};
|
|
1321
1336
|
export declare const sendTransfer: (options: SendTransferOptions) => Promise<TransactionResult>;
|
|
1322
1337
|
type SendBridgeOutOptions = {
|
|
@@ -1332,6 +1347,7 @@ type SendBridgeOutOptions = {
|
|
|
1332
1347
|
toToken: WormholeToken & {
|
|
1333
1348
|
chain: "Solana";
|
|
1334
1349
|
};
|
|
1350
|
+
feeConfig: Awaited<ReturnType<typeof getBridgeOutFee>>;
|
|
1335
1351
|
};
|
|
1336
1352
|
type WormholeToken = {
|
|
1337
1353
|
chain: Chain;
|
package/esm/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { sha256 } from "@noble/hashes/sha2";
|
|
|
7
7
|
import { fromLegacyPublicKey } from "@solana/compat";
|
|
8
8
|
import { generateKeyPair, getAddressFromPublicKey, getProgramDerivedAddress, signatureBytes, verifySignature, } from "@solana/kit";
|
|
9
9
|
import { createAssociatedTokenAccountIdempotentInstruction, getAssociatedTokenAddressSync, getMint, } from "@solana/spl-token";
|
|
10
|
-
import { Connection, Ed25519Program, Keypair, PublicKey, } from "@solana/web3.js";
|
|
10
|
+
import { ComputeBudgetProgram, Connection, Ed25519Program, Keypair, PublicKey, } from "@solana/web3.js";
|
|
11
11
|
import { Wormhole, wormhole, routes } from "@wormhole-foundation/sdk";
|
|
12
12
|
import solanaSdk from "@wormhole-foundation/sdk/solana";
|
|
13
13
|
import { contracts } from "@wormhole-foundation/sdk-base";
|
|
@@ -29,9 +29,9 @@ const TOKENLESS_PERMISSIONS_VALUE = "this app may not spend any tokens";
|
|
|
29
29
|
const CURRENT_MAJOR = "0";
|
|
30
30
|
const CURRENT_MINOR = "3";
|
|
31
31
|
const CURRENT_INTENT_TRANSFER_MAJOR = "0";
|
|
32
|
-
const CURRENT_INTENT_TRANSFER_MINOR = "
|
|
32
|
+
const CURRENT_INTENT_TRANSFER_MINOR = "2";
|
|
33
33
|
const CURRENT_BRIDGE_OUT_MAJOR = "0";
|
|
34
|
-
const CURRENT_BRIDGE_OUT_MINOR = "
|
|
34
|
+
const CURRENT_BRIDGE_OUT_MINOR = "2";
|
|
35
35
|
const SESSION_ESTABLISHMENT_LOOKUP_TABLE_ADDRESS = {
|
|
36
36
|
[Network.Testnet]: "B8cUjJMqaWWTNNSTXBmeptjWswwCH1gTSCRYv4nu7kJW",
|
|
37
37
|
[Network.Mainnet]: undefined,
|
|
@@ -430,7 +430,10 @@ const BRIDGING_ADDRESS_LOOKUP_TABLE = {
|
|
|
430
430
|
// USDC
|
|
431
431
|
ELNbJ1RtERV2fjtuZjbTscDekWhVzkQ1LjmiPsxp5uND: "4FCi6LptexBdZtaePsoCMeb1XpCijxnWu96g5LsSb6WP",
|
|
432
432
|
},
|
|
433
|
-
[Network.Mainnet]:
|
|
433
|
+
[Network.Mainnet]: {
|
|
434
|
+
// USDC
|
|
435
|
+
uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG: "84k3mfNjmyinpZwyev7F15ChEW3Kqa3NoUkCJXXs4qkw",
|
|
436
|
+
},
|
|
434
437
|
};
|
|
435
438
|
const buildStartSessionInstruction = async (options, sessionKey, tokens) => {
|
|
436
439
|
const instruction = new SessionManagerProgram(new AnchorProvider(options.context.connection, {}, {})).methods
|
|
@@ -483,12 +486,50 @@ const EstablishSessionResult = {
|
|
|
483
486
|
error,
|
|
484
487
|
}),
|
|
485
488
|
};
|
|
489
|
+
const USDC_MINT = {
|
|
490
|
+
[Network.Mainnet]: "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
|
|
491
|
+
[Network.Testnet]: "ELNbJ1RtERV2fjtuZjbTscDekWhVzkQ1LjmiPsxp5uND",
|
|
492
|
+
};
|
|
493
|
+
const USDC_DECIMALS = 6;
|
|
494
|
+
export const getTransferFee = async (context) => {
|
|
495
|
+
const { fee, ...config } = await getFee(context);
|
|
496
|
+
return {
|
|
497
|
+
...config,
|
|
498
|
+
fee: fee.intrachainTransfer,
|
|
499
|
+
};
|
|
500
|
+
};
|
|
501
|
+
export const getBridgeOutFee = async (context) => {
|
|
502
|
+
const { fee, ...config } = await getFee(context);
|
|
503
|
+
return {
|
|
504
|
+
...config,
|
|
505
|
+
fee: fee.bridgeTransfer,
|
|
506
|
+
};
|
|
507
|
+
};
|
|
508
|
+
const getFee = async (context) => {
|
|
509
|
+
const program = new IntentTransferProgram(new AnchorProvider(context.connection, {}, {}));
|
|
510
|
+
const umi = createUmi(context.connection.rpcEndpoint);
|
|
511
|
+
const usdcMintAddress = USDC_MINT[context.network];
|
|
512
|
+
const usdcMint = new PublicKey(usdcMintAddress);
|
|
513
|
+
const [feeConfigPda] = PublicKey.findProgramAddressSync([Buffer.from("fee_config"), usdcMint.toBytes()], program.programId);
|
|
514
|
+
const feeConfig = await program.account.feeConfig.fetch(feeConfigPda);
|
|
515
|
+
return {
|
|
516
|
+
metadata: findMetadataPda(umi, {
|
|
517
|
+
mint: metaplexPublicKey(usdcMintAddress),
|
|
518
|
+
})[0],
|
|
519
|
+
mint: usdcMint,
|
|
520
|
+
symbolOrMint: context.network === Network.Mainnet ? "USDC.s" : "USDC",
|
|
521
|
+
decimals: USDC_DECIMALS,
|
|
522
|
+
fee: {
|
|
523
|
+
intrachainTransfer: BigInt(feeConfig.intrachainTransferFee.toString()),
|
|
524
|
+
bridgeTransfer: BigInt(feeConfig.bridgeTransferFee.toString()),
|
|
525
|
+
},
|
|
526
|
+
};
|
|
527
|
+
};
|
|
486
528
|
const TRANSFER_MESSAGE_HEADER = `Fogo Transfer:
|
|
487
529
|
Signing this intent will transfer the tokens as described below.
|
|
488
530
|
`;
|
|
489
531
|
export const sendTransfer = async (options) => {
|
|
490
532
|
const sourceAta = getAssociatedTokenAddressSync(options.mint, options.walletPublicKey);
|
|
491
|
-
const destinationAta = getAssociatedTokenAddressSync(options.mint, options.recipient);
|
|
492
533
|
const program = new IntentTransferProgram(new AnchorProvider(options.context.connection, {}, {}));
|
|
493
534
|
const umi = createUmi(options.context.connection.rpcEndpoint);
|
|
494
535
|
const metaplexMint = metaplexPublicKey(options.mint.toBase58());
|
|
@@ -496,12 +537,14 @@ export const sendTransfer = async (options) => {
|
|
|
496
537
|
const metadata = await safeFetchMetadata(umi, metadataAddress);
|
|
497
538
|
const symbol = metadata?.symbol ?? undefined;
|
|
498
539
|
return options.context.sendTransaction(undefined, [
|
|
499
|
-
|
|
500
|
-
await buildTransferIntentInstruction(program, options, symbol),
|
|
540
|
+
await buildTransferIntentInstruction(program, options, symbol, options.feeConfig.symbolOrMint, amountToString(options.feeConfig.fee, options.feeConfig.decimals)),
|
|
501
541
|
await program.methods
|
|
502
542
|
.sendTokens()
|
|
503
543
|
.accounts({
|
|
504
|
-
|
|
544
|
+
destinationOwner: options.recipient,
|
|
545
|
+
feeMetadata: options.feeConfig.metadata,
|
|
546
|
+
feeMint: options.feeConfig.mint,
|
|
547
|
+
feeSource: getAssociatedTokenAddressSync(options.feeConfig.mint, options.walletPublicKey),
|
|
505
548
|
mint: options.mint,
|
|
506
549
|
source: sourceAta,
|
|
507
550
|
sponsor: options.context.payer,
|
|
@@ -511,7 +554,7 @@ export const sendTransfer = async (options) => {
|
|
|
511
554
|
.instruction(),
|
|
512
555
|
]);
|
|
513
556
|
};
|
|
514
|
-
const buildTransferIntentInstruction = async (program, options, symbol) => {
|
|
557
|
+
const buildTransferIntentInstruction = async (program, options, symbol, feeToken, feeAmount) => {
|
|
515
558
|
const [nonce, { decimals }] = await Promise.all([
|
|
516
559
|
getNonce(program, options.walletPublicKey, NonceType.Transfer),
|
|
517
560
|
getMint(options.context.connection, options.mint),
|
|
@@ -524,6 +567,8 @@ const buildTransferIntentInstruction = async (program, options, symbol) => {
|
|
|
524
567
|
token: symbol ?? options.mint.toBase58(),
|
|
525
568
|
amount: amountToString(options.amount, decimals),
|
|
526
569
|
recipient: options.recipient.toBase58(),
|
|
570
|
+
fee_token: feeToken,
|
|
571
|
+
fee_amount: feeAmount,
|
|
527
572
|
nonce: nonce === null ? "1" : nonce.nonce.add(new BN(1)).toString(),
|
|
528
573
|
}),
|
|
529
574
|
].join("\n"));
|
|
@@ -537,6 +582,7 @@ const buildTransferIntentInstruction = async (program, options, symbol) => {
|
|
|
537
582
|
const BRIDGE_OUT_MESSAGE_HEADER = `Fogo Bridge Transfer:
|
|
538
583
|
Signing this intent will bridge out the tokens as described below.
|
|
539
584
|
`;
|
|
585
|
+
const BRIDGE_OUT_CUS = 220_000;
|
|
540
586
|
export const bridgeOut = async (options) => {
|
|
541
587
|
const { wh, route, transferRequest, transferParams, decimals } = await buildWormholeTransfer(options, options.context.connection);
|
|
542
588
|
// @ts-expect-error the wormhole client types are incorrect and do not
|
|
@@ -547,34 +593,46 @@ export const bridgeOut = async (options) => {
|
|
|
547
593
|
const metaplexMint = metaplexPublicKey(options.fromToken.mint.toBase58());
|
|
548
594
|
const metadataAddress = findMetadataPda(umi, { mint: metaplexMint })[0];
|
|
549
595
|
const outboxItem = Keypair.generate();
|
|
550
|
-
const [metadata, nttPdas] = await Promise.all([
|
|
596
|
+
const [metadata, nttPdas, destinationAtaExists] = await Promise.all([
|
|
551
597
|
safeFetchMetadata(umi, metadataAddress),
|
|
552
598
|
getNttPdas(options, wh, program, outboxItem.publicKey, new PublicKey(quote.payeeAddress)),
|
|
599
|
+
getDestinationAtaExists(options.context, options.toToken.mint, options.walletPublicKey),
|
|
600
|
+
]);
|
|
601
|
+
const instructions = await Promise.all([
|
|
602
|
+
buildBridgeOutIntent(program, options, decimals, metadata?.symbol, options.feeConfig.symbolOrMint, amountToString(options.feeConfig.fee, options.feeConfig.decimals)),
|
|
603
|
+
program.methods
|
|
604
|
+
.bridgeNttTokens({
|
|
605
|
+
payDestinationAtaRent: !destinationAtaExists,
|
|
606
|
+
signedQuoteBytes: Buffer.from(quote.signedQuote),
|
|
607
|
+
})
|
|
608
|
+
.accounts({
|
|
609
|
+
sponsor: options.context.payer,
|
|
610
|
+
mint: options.fromToken.mint,
|
|
611
|
+
metadata: metadata?.symbol === undefined
|
|
612
|
+
? // eslint-disable-next-line unicorn/no-null
|
|
613
|
+
null
|
|
614
|
+
: new PublicKey(metadataAddress),
|
|
615
|
+
source: getAssociatedTokenAddressSync(options.fromToken.mint, options.walletPublicKey),
|
|
616
|
+
ntt: nttPdas,
|
|
617
|
+
feeMetadata: options.feeConfig.metadata,
|
|
618
|
+
feeMint: options.feeConfig.mint,
|
|
619
|
+
feeSource: getAssociatedTokenAddressSync(options.feeConfig.mint, options.walletPublicKey),
|
|
620
|
+
})
|
|
621
|
+
.instruction(),
|
|
553
622
|
]);
|
|
554
|
-
const bridgeInstruction = await program.methods
|
|
555
|
-
.bridgeNttTokens({
|
|
556
|
-
execAmount: new BN(quote.estimatedCost.toString()),
|
|
557
|
-
relayInstructions: Buffer.from(quote.relayInstructions),
|
|
558
|
-
signedQuoteBytes: Buffer.from(quote.signedQuote),
|
|
559
|
-
})
|
|
560
|
-
.accounts({
|
|
561
|
-
sponsor: options.context.payer,
|
|
562
|
-
mint: options.fromToken.mint,
|
|
563
|
-
metadata:
|
|
564
|
-
// eslint-disable-next-line unicorn/no-null
|
|
565
|
-
metadata?.symbol === undefined ? null : new PublicKey(metadataAddress),
|
|
566
|
-
source: getAssociatedTokenAddressSync(options.fromToken.mint, options.walletPublicKey),
|
|
567
|
-
ntt: nttPdas,
|
|
568
|
-
})
|
|
569
|
-
.instruction();
|
|
570
623
|
return options.context.sendTransaction(options.sessionKey, [
|
|
571
|
-
|
|
572
|
-
|
|
624
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: BRIDGE_OUT_CUS }),
|
|
625
|
+
...instructions,
|
|
573
626
|
], {
|
|
574
627
|
extraSigners: [outboxItem],
|
|
575
628
|
addressLookupTable: BRIDGING_ADDRESS_LOOKUP_TABLE[options.context.network]?.[options.fromToken.mint.toBase58()],
|
|
576
629
|
});
|
|
577
630
|
};
|
|
631
|
+
const getDestinationAtaExists = async (context, token, wallet) => {
|
|
632
|
+
const solanaConnection = await context.getSolanaConnection();
|
|
633
|
+
const ataAccount = await solanaConnection.getAccountInfo(getAssociatedTokenAddressSync(token, wallet));
|
|
634
|
+
return ataAccount !== null;
|
|
635
|
+
};
|
|
578
636
|
// Here we use the Wormhole SDKs to produce the wormhole pdas that are needed
|
|
579
637
|
// for the bridge out transaction. Currently this is using wormhole SDK apis
|
|
580
638
|
// that are _technically_ public but it seems likely these are not considered to
|
|
@@ -592,6 +650,10 @@ const getNttPdas = async (options, wh, program, outboxItemPublicKey, quotePayeeA
|
|
|
592
650
|
const transceiverPdas = NTT.transceiverPdas(options.fromToken.manager);
|
|
593
651
|
const [intentTransferSetterPda] = PublicKey.findProgramAddressSync([Buffer.from("intent_transfer")], program.programId);
|
|
594
652
|
const wormholePdas = utils.getWormholeDerivedAccounts(options.fromToken.manager, coreBridgeContract);
|
|
653
|
+
const [registeredTransceiverPda] = PublicKey.findProgramAddressSync([
|
|
654
|
+
Buffer.from("registered_transceiver"),
|
|
655
|
+
options.fromToken.manager.toBytes(),
|
|
656
|
+
], options.fromToken.manager);
|
|
595
657
|
return {
|
|
596
658
|
emitter: transceiverPdas.emitterAccount(),
|
|
597
659
|
nttConfig: pdas.configAccount(),
|
|
@@ -604,14 +666,15 @@ const getNttPdas = async (options, wh, program, outboxItemPublicKey, quotePayeeA
|
|
|
604
666
|
nttSessionAuthority: pdas.sessionAuthority(intentTransferSetterPda, NTT.transferArgs(options.amount, Wormhole.chainAddress("Solana", options.walletPublicKey.toBase58()), false)),
|
|
605
667
|
nttTokenAuthority: pdas.tokenAuthority(),
|
|
606
668
|
payeeNttWithExecutor: quotePayeeAddress,
|
|
607
|
-
transceiver:
|
|
669
|
+
transceiver: registeredTransceiverPda,
|
|
670
|
+
wormholeProgram: coreBridgeContract,
|
|
608
671
|
wormholeBridge: wormholePdas.wormholeBridge,
|
|
609
672
|
wormholeFeeCollector: wormholePdas.wormholeFeeCollector,
|
|
610
673
|
wormholeMessage: transceiverPdas.wormholeMessageAccount(outboxItemPublicKey),
|
|
611
674
|
wormholeSequence: wormholePdas.wormholeSequence,
|
|
612
675
|
};
|
|
613
676
|
};
|
|
614
|
-
const buildBridgeOutIntent = async (program, options, decimals, symbol) => {
|
|
677
|
+
const buildBridgeOutIntent = async (program, options, decimals, symbol, feeToken, feeAmount) => {
|
|
615
678
|
const nonce = await getNonce(program, options.walletPublicKey, NonceType.Bridge);
|
|
616
679
|
const message = new TextEncoder().encode([
|
|
617
680
|
BRIDGE_OUT_MESSAGE_HEADER,
|
|
@@ -622,6 +685,8 @@ const buildBridgeOutIntent = async (program, options, decimals, symbol) => {
|
|
|
622
685
|
token: symbol ?? options.fromToken.mint.toBase58(),
|
|
623
686
|
amount: amountToString(options.amount, decimals),
|
|
624
687
|
recipient_address: options.walletPublicKey.toBase58(),
|
|
688
|
+
fee_token: feeToken,
|
|
689
|
+
fee_amount: feeAmount,
|
|
625
690
|
nonce: nonce === null ? "1" : nonce.nonce.add(new BN(1)).toString(),
|
|
626
691
|
}),
|
|
627
692
|
].join("\n"));
|
|
@@ -647,7 +712,7 @@ export const bridgeIn = async (options) => {
|
|
|
647
712
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
648
713
|
transaction.transaction, solanaConnection,
|
|
649
714
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
650
|
-
{ signers: transaction.signers
|
|
715
|
+
{ signers: transaction.signers }))),
|
|
651
716
|
}, quote, Wormhole.chainAddress("Fogo", options.walletPublicKey.toBase58())));
|
|
652
717
|
}
|
|
653
718
|
else {
|
|
@@ -655,8 +720,11 @@ export const bridgeIn = async (options) => {
|
|
|
655
720
|
}
|
|
656
721
|
};
|
|
657
722
|
const buildWormholeTransfer = async (options, connection) => {
|
|
723
|
+
const solanaConnection = await options.context.getSolanaConnection();
|
|
658
724
|
const [wh, { decimals }] = await Promise.all([
|
|
659
|
-
wormhole(NETWORK_TO_WORMHOLE_NETWORK[options.context.network], [solanaSdk]
|
|
725
|
+
wormhole(NETWORK_TO_WORMHOLE_NETWORK[options.context.network], [solanaSdk], {
|
|
726
|
+
chains: { Solana: { rpc: solanaConnection.rpcEndpoint } },
|
|
727
|
+
}),
|
|
660
728
|
getMint(connection, options.fromToken.mint),
|
|
661
729
|
]);
|
|
662
730
|
const Route = nttExecutorRoute({
|
|
@@ -691,6 +759,7 @@ const buildWormholeTransfer = async (options, connection) => {
|
|
|
691
759
|
});
|
|
692
760
|
const route = new Route(wh);
|
|
693
761
|
const transferRequest = await routes.RouteTransferRequest.create(wh, {
|
|
762
|
+
recipient: Wormhole.chainAddress(options.toToken.chain, options.walletPublicKey.toBase58()),
|
|
694
763
|
source: Wormhole.tokenId(options.fromToken.chain, options.fromToken.mint.toBase58()),
|
|
695
764
|
destination: Wormhole.tokenId(options.toToken.chain, options.toToken.mint.toBase58()),
|
|
696
765
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fogo/sessions-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
4
4
|
"description": "A set of utilities for integrating with Fogo sessions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fogo",
|
|
@@ -44,6 +44,6 @@
|
|
|
44
44
|
"bn.js": "^5.1.2",
|
|
45
45
|
"bs58": "^6.0.0",
|
|
46
46
|
"zod": "^3.25.62",
|
|
47
|
-
"@fogo/sessions-idls": "^0.0.
|
|
47
|
+
"@fogo/sessions-idls": "^0.0.9"
|
|
48
48
|
}
|
|
49
49
|
}
|