@fogo/sessions-sdk 0.0.9 → 0.0.10
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/adapter.d.ts +2 -2
- package/cjs/adapter.js +43 -23
- package/cjs/index.d.ts +9 -0
- package/cjs/index.js +68 -5
- package/esm/adapter.d.ts +2 -2
- package/esm/adapter.js +43 -23
- package/esm/index.d.ts +9 -0
- package/esm/index.js +68 -6
- package/package.json +2 -2
package/cjs/adapter.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type SessionAdapter = {
|
|
|
6
6
|
connection: Connection;
|
|
7
7
|
payer: PublicKey;
|
|
8
8
|
domain: string;
|
|
9
|
-
sendTransaction: (sessionKey: CryptoKeyPair, instructions: (TransactionInstruction | IInstruction)[] | VersionedTransaction | Transaction) => Promise<TransactionResult>;
|
|
9
|
+
sendTransaction: (sessionKey: CryptoKeyPair | undefined, instructions: (TransactionInstruction | IInstruction)[] | VersionedTransaction | Transaction) => Promise<TransactionResult>;
|
|
10
10
|
};
|
|
11
11
|
export declare enum TransactionResultType {
|
|
12
12
|
Success = 0,
|
|
@@ -31,7 +31,7 @@ export declare const createSolanaWalletAdapter: (options: {
|
|
|
31
31
|
} & ({
|
|
32
32
|
paymaster?: string | URL | undefined;
|
|
33
33
|
} | {
|
|
34
|
-
sendToPaymaster: (transaction: Transaction) => Promise<
|
|
34
|
+
sendToPaymaster: (transaction: Transaction) => Promise<TransactionResult>;
|
|
35
35
|
sponsor: PublicKey;
|
|
36
36
|
})) => Promise<SessionAdapter>;
|
|
37
37
|
export {};
|
package/cjs/adapter.js
CHANGED
|
@@ -38,31 +38,34 @@ const createSolanaWalletAdapter = async (options) => {
|
|
|
38
38
|
sendTransaction: async (sessionKey, instructions) => {
|
|
39
39
|
const rpc = (0, kit_1.createSolanaRpc)(options.connection.rpcEndpoint);
|
|
40
40
|
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
41
|
-
|
|
42
|
-
const transaction = Array.isArray(instructions)
|
|
43
|
-
? await (0, kit_1.partiallySignTransactionMessageWithSigners)((0, kit_1.pipe)((0, kit_1.createTransactionMessage)({ version: 0 }), (tx) => (0, kit_1.setTransactionMessageFeePayer)((0, compat_1.fromLegacyPublicKey)(sponsor), tx), (tx) => (0, kit_1.setTransactionMessageLifetimeUsingBlockhash)(latestBlockhash, tx), (tx) => (0, kit_1.appendTransactionMessageInstructions)(instructions.map((instruction) => instruction instanceof web3_js_1.TransactionInstruction
|
|
44
|
-
? (0, compat_1.fromLegacyTransactionInstruction)(instruction)
|
|
45
|
-
: instruction), tx), (tx) => (0, kit_1.compressTransactionMessageUsingAddressLookupTables)(tx, Object.fromEntries(addressLookupTables?.map((table) => [
|
|
46
|
-
(0, compat_1.fromLegacyPublicKey)(table.key),
|
|
47
|
-
table.state.addresses.map((address) => (0, compat_1.fromLegacyPublicKey)(address)),
|
|
48
|
-
]) ?? [])), (tx) => (0, kit_1.addSignersToTransactionMessage)([sessionKeySigner], tx)))
|
|
49
|
-
: await (0, kit_1.partiallySignTransaction)([sessionKey], instructions instanceof web3_js_1.VersionedTransaction
|
|
50
|
-
? (0, compat_1.fromVersionedTransaction)(instructions)
|
|
51
|
-
: instructions);
|
|
52
|
-
const signature = await sendToPaymaster(options, transaction);
|
|
53
|
-
const lastValidBlockHeight = await rpc.getSlot().send();
|
|
54
|
-
const confirmationResult = await options.connection.confirmTransaction({
|
|
55
|
-
signature,
|
|
56
|
-
blockhash: latestBlockhash.blockhash.toString(),
|
|
57
|
-
lastValidBlockHeight: Number(lastValidBlockHeight),
|
|
58
|
-
});
|
|
59
|
-
return confirmationResult.value.err === null
|
|
60
|
-
? TransactionResult.Success(signature)
|
|
61
|
-
: TransactionResult.Failed(signature, confirmationResult.value.err);
|
|
41
|
+
return await sendToPaymaster(options, await buildTransaction(latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables));
|
|
62
42
|
},
|
|
63
43
|
};
|
|
64
44
|
};
|
|
65
45
|
exports.createSolanaWalletAdapter = createSolanaWalletAdapter;
|
|
46
|
+
const buildTransaction = async (latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables) => {
|
|
47
|
+
const sessionKeySigner = sessionKey
|
|
48
|
+
? await (0, kit_1.createSignerFromKeyPair)(sessionKey)
|
|
49
|
+
: undefined;
|
|
50
|
+
if (Array.isArray(instructions)) {
|
|
51
|
+
return (0, kit_1.partiallySignTransactionMessageWithSigners)((0, kit_1.pipe)((0, kit_1.createTransactionMessage)({ version: 0 }), (tx) => (0, kit_1.setTransactionMessageFeePayer)((0, compat_1.fromLegacyPublicKey)(sponsor), tx), (tx) => (0, kit_1.setTransactionMessageLifetimeUsingBlockhash)(latestBlockhash, tx), (tx) => (0, kit_1.appendTransactionMessageInstructions)(instructions.map((instruction) => instruction instanceof web3_js_1.TransactionInstruction
|
|
52
|
+
? (0, compat_1.fromLegacyTransactionInstruction)(instruction)
|
|
53
|
+
: instruction), tx), (tx) => (0, kit_1.compressTransactionMessageUsingAddressLookupTables)(tx, Object.fromEntries(addressLookupTables?.map((table) => [
|
|
54
|
+
(0, compat_1.fromLegacyPublicKey)(table.key),
|
|
55
|
+
table.state.addresses.map((address) => (0, compat_1.fromLegacyPublicKey)(address)),
|
|
56
|
+
]) ?? [])), (tx) => sessionKeySigner === undefined
|
|
57
|
+
? tx
|
|
58
|
+
: (0, kit_1.addSignersToTransactionMessage)([sessionKeySigner], tx)));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const tx = instructions instanceof web3_js_1.VersionedTransaction
|
|
62
|
+
? (0, compat_1.fromVersionedTransaction)(instructions)
|
|
63
|
+
: instructions;
|
|
64
|
+
return sessionKey === undefined
|
|
65
|
+
? tx
|
|
66
|
+
: (0, kit_1.partiallySignTransaction)([sessionKey], tx);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
66
69
|
const getSponsor = async (options) => {
|
|
67
70
|
if ("sponsor" in options) {
|
|
68
71
|
return options.sponsor;
|
|
@@ -72,12 +75,29 @@ const getSponsor = async (options) => {
|
|
|
72
75
|
return new web3_js_1.PublicKey(zod_1.z.string().parse(await response.text()));
|
|
73
76
|
}
|
|
74
77
|
};
|
|
78
|
+
const sponsorAndSendResponseSchema = zod_1.z
|
|
79
|
+
.discriminatedUnion("type", [
|
|
80
|
+
zod_1.z.object({
|
|
81
|
+
type: zod_1.z.literal("success"),
|
|
82
|
+
signature: zod_1.z.string(),
|
|
83
|
+
}),
|
|
84
|
+
zod_1.z.object({
|
|
85
|
+
type: zod_1.z.literal("failed"),
|
|
86
|
+
signature: zod_1.z.string(),
|
|
87
|
+
error: zod_1.z.object({}),
|
|
88
|
+
}),
|
|
89
|
+
])
|
|
90
|
+
.transform((data) => {
|
|
91
|
+
return data.type === "success"
|
|
92
|
+
? TransactionResult.Success(data.signature)
|
|
93
|
+
: TransactionResult.Failed(data.signature, data.error);
|
|
94
|
+
});
|
|
75
95
|
const sendToPaymaster = async (options, transaction) => {
|
|
76
96
|
if ("sendToPaymaster" in options) {
|
|
77
97
|
return options.sendToPaymaster(transaction);
|
|
78
98
|
}
|
|
79
99
|
else {
|
|
80
|
-
const response = await fetch(new URL("/api/sponsor_and_send", options.paymaster ?? DEFAULT_PAYMASTER), {
|
|
100
|
+
const response = await fetch(new URL("/api/sponsor_and_send?confirm=true", options.paymaster ?? DEFAULT_PAYMASTER), {
|
|
81
101
|
method: "POST",
|
|
82
102
|
headers: {
|
|
83
103
|
"Content-Type": "application/json",
|
|
@@ -87,7 +107,7 @@ const sendToPaymaster = async (options, transaction) => {
|
|
|
87
107
|
}),
|
|
88
108
|
});
|
|
89
109
|
if (response.status === 200) {
|
|
90
|
-
return response.
|
|
110
|
+
return sponsorAndSendResponseSchema.parse(await response.json());
|
|
91
111
|
}
|
|
92
112
|
else {
|
|
93
113
|
throw new PaymasterResponseError(response.status, await response.text());
|
package/cjs/index.d.ts
CHANGED
|
@@ -290,3 +290,12 @@ export type Session = {
|
|
|
290
290
|
sendTransaction: (instructions: Parameters<SessionAdapter["sendTransaction"]>[1]) => Promise<TransactionResult>;
|
|
291
291
|
sessionInfo: z.infer<typeof sessionInfoSchema>;
|
|
292
292
|
};
|
|
293
|
+
type SendTransferOptions = {
|
|
294
|
+
adapter: SessionAdapter;
|
|
295
|
+
walletPublicKey: PublicKey;
|
|
296
|
+
signMessage: (message: Uint8Array) => Promise<Uint8Array>;
|
|
297
|
+
mint: PublicKey;
|
|
298
|
+
amount: bigint;
|
|
299
|
+
recipient: PublicKey;
|
|
300
|
+
};
|
|
301
|
+
export declare const sendTransfer: (options: SendTransferOptions) => Promise<TransactionResult>;
|
package/cjs/index.js
CHANGED
|
@@ -3,13 +3,14 @@ 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.SessionResultType = exports.getDomainRecordAddress = exports.AuthorizedTokens = exports.AuthorizedProgramsType = exports.getSessionAccount = exports.reestablishSession = exports.replaceSession = exports.establishSession = exports.createSolanaWalletAdapter = exports.TransactionResultType = void 0;
|
|
6
|
+
exports.sendTransfer = exports.SessionResultType = exports.getDomainRecordAddress = exports.AuthorizedTokens = exports.AuthorizedProgramsType = exports.getSessionAccount = exports.reestablishSession = exports.replaceSession = exports.establishSession = exports.createSolanaWalletAdapter = exports.TransactionResultType = 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");
|
|
10
10
|
const umi_1 = require("@metaplex-foundation/umi");
|
|
11
11
|
const umi_bundle_defaults_1 = require("@metaplex-foundation/umi-bundle-defaults");
|
|
12
12
|
const sha2_1 = require("@noble/hashes/sha2");
|
|
13
|
+
const compat_1 = require("@solana/compat");
|
|
13
14
|
const kit_1 = require("@solana/kit");
|
|
14
15
|
const spl_token_1 = require("@solana/spl-token");
|
|
15
16
|
const web3_js_1 = require("@solana/web3.js");
|
|
@@ -26,6 +27,8 @@ const UNLIMITED_TOKEN_PERMISSIONS_VALUE = "this app may spend any amount of any
|
|
|
26
27
|
const TOKENLESS_PERMISSIONS_VALUE = "this app may not spend any tokens";
|
|
27
28
|
const CURRENT_MAJOR = "0";
|
|
28
29
|
const CURRENT_MINOR = "1";
|
|
30
|
+
const CURRENT_INTENT_TRANSFER_MAJOR = "0";
|
|
31
|
+
const CURRENT_INTENT_TRANSFER_MINOR = "1";
|
|
29
32
|
const establishSession = async (options) => {
|
|
30
33
|
const sessionKey = await (0, kit_1.generateKeyPair)();
|
|
31
34
|
if (options.unlimited) {
|
|
@@ -155,10 +158,11 @@ var AuthorizedTokens;
|
|
|
155
158
|
AuthorizedTokens[AuthorizedTokens["All"] = 0] = "All";
|
|
156
159
|
AuthorizedTokens[AuthorizedTokens["Specific"] = 1] = "Specific";
|
|
157
160
|
})(AuthorizedTokens || (exports.AuthorizedTokens = AuthorizedTokens = {}));
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
var SymbolOrMintType;
|
|
162
|
+
(function (SymbolOrMintType) {
|
|
163
|
+
SymbolOrMintType[SymbolOrMintType["Symbol"] = 0] = "Symbol";
|
|
164
|
+
SymbolOrMintType[SymbolOrMintType["Mint"] = 1] = "Mint";
|
|
165
|
+
})(SymbolOrMintType || (SymbolOrMintType = {}));
|
|
162
166
|
const SymbolOrMint = {
|
|
163
167
|
Symbol: (symbol) => ({
|
|
164
168
|
type: SymbolOrMintType.Symbol,
|
|
@@ -303,3 +307,62 @@ const EstablishSessionResult = {
|
|
|
303
307
|
error,
|
|
304
308
|
}),
|
|
305
309
|
};
|
|
310
|
+
const TRANSFER_MESSAGE_HEADER = `Fogo Transfer:
|
|
311
|
+
Signing this intent will transfer the tokens as described below.
|
|
312
|
+
`;
|
|
313
|
+
const sendTransfer = async (options) => {
|
|
314
|
+
const sourceAta = (0, spl_token_1.getAssociatedTokenAddressSync)(options.mint, options.walletPublicKey);
|
|
315
|
+
const destinationAta = (0, spl_token_1.getAssociatedTokenAddressSync)(options.mint, options.recipient);
|
|
316
|
+
const program = new sessions_idls_1.IntentTransferProgram(new anchor_1.AnchorProvider(options.adapter.connection, {}, {}));
|
|
317
|
+
const umi = (0, umi_bundle_defaults_1.createUmi)(options.adapter.connection.rpcEndpoint);
|
|
318
|
+
const metaplexMint = (0, umi_1.publicKey)(options.mint.toBase58());
|
|
319
|
+
const metadataAddress = (0, mpl_token_metadata_1.findMetadataPda)(umi, { mint: metaplexMint })[0];
|
|
320
|
+
const metadata = await (0, mpl_token_metadata_1.safeFetchMetadata)(umi, metadataAddress);
|
|
321
|
+
const symbol = metadata?.symbol ?? undefined;
|
|
322
|
+
return options.adapter.sendTransaction(undefined, [
|
|
323
|
+
(0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(options.adapter.payer, destinationAta, options.recipient, options.mint),
|
|
324
|
+
await buildTransferIntentInstruction(program, options, symbol),
|
|
325
|
+
await program.methods
|
|
326
|
+
.sendTokens()
|
|
327
|
+
.accounts({
|
|
328
|
+
destination: destinationAta,
|
|
329
|
+
mint: options.mint,
|
|
330
|
+
source: sourceAta,
|
|
331
|
+
sponsor: options.adapter.payer,
|
|
332
|
+
// eslint-disable-next-line unicorn/no-null
|
|
333
|
+
metadata: symbol === undefined ? null : new web3_js_1.PublicKey(metadataAddress),
|
|
334
|
+
})
|
|
335
|
+
.instruction(),
|
|
336
|
+
]);
|
|
337
|
+
};
|
|
338
|
+
exports.sendTransfer = sendTransfer;
|
|
339
|
+
const buildTransferIntentInstruction = async (program, options, symbol) => {
|
|
340
|
+
const [nonce, { decimals }] = await Promise.all([
|
|
341
|
+
getNonce(program, options.walletPublicKey),
|
|
342
|
+
(0, spl_token_1.getMint)(options.adapter.connection, options.mint),
|
|
343
|
+
]);
|
|
344
|
+
const message = new TextEncoder().encode([
|
|
345
|
+
TRANSFER_MESSAGE_HEADER,
|
|
346
|
+
serializeKV({
|
|
347
|
+
version: `${CURRENT_INTENT_TRANSFER_MAJOR}.${CURRENT_INTENT_TRANSFER_MINOR}`,
|
|
348
|
+
chain_id: options.adapter.chainId,
|
|
349
|
+
token: symbol ?? options.mint.toBase58(),
|
|
350
|
+
amount: amountToString(options.amount, decimals),
|
|
351
|
+
recipient: options.recipient.toBase58(),
|
|
352
|
+
nonce: nonce === null ? "1" : nonce.nonce.add(new bn_js_1.default(1)).toString(),
|
|
353
|
+
}),
|
|
354
|
+
].join("\n"));
|
|
355
|
+
const intentSignature = await options.signMessage(message);
|
|
356
|
+
return web3_js_1.Ed25519Program.createInstructionWithPublicKey({
|
|
357
|
+
publicKey: options.walletPublicKey.toBytes(),
|
|
358
|
+
signature: intentSignature,
|
|
359
|
+
message: message,
|
|
360
|
+
});
|
|
361
|
+
};
|
|
362
|
+
const getNonce = async (program, walletPublicKey) => {
|
|
363
|
+
const [noncePda] = await (0, kit_1.getProgramDerivedAddress)({
|
|
364
|
+
programAddress: (0, compat_1.fromLegacyPublicKey)(program.programId),
|
|
365
|
+
seeds: [Buffer.from("nonce"), walletPublicKey.toBuffer()],
|
|
366
|
+
});
|
|
367
|
+
return program.account.nonce.fetchNullable(noncePda);
|
|
368
|
+
};
|
package/esm/adapter.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type SessionAdapter = {
|
|
|
6
6
|
connection: Connection;
|
|
7
7
|
payer: PublicKey;
|
|
8
8
|
domain: string;
|
|
9
|
-
sendTransaction: (sessionKey: CryptoKeyPair, instructions: (TransactionInstruction | IInstruction)[] | VersionedTransaction | Transaction) => Promise<TransactionResult>;
|
|
9
|
+
sendTransaction: (sessionKey: CryptoKeyPair | undefined, instructions: (TransactionInstruction | IInstruction)[] | VersionedTransaction | Transaction) => Promise<TransactionResult>;
|
|
10
10
|
};
|
|
11
11
|
export declare enum TransactionResultType {
|
|
12
12
|
Success = 0,
|
|
@@ -31,7 +31,7 @@ export declare const createSolanaWalletAdapter: (options: {
|
|
|
31
31
|
} & ({
|
|
32
32
|
paymaster?: string | URL | undefined;
|
|
33
33
|
} | {
|
|
34
|
-
sendToPaymaster: (transaction: Transaction) => Promise<
|
|
34
|
+
sendToPaymaster: (transaction: Transaction) => Promise<TransactionResult>;
|
|
35
35
|
sponsor: PublicKey;
|
|
36
36
|
})) => Promise<SessionAdapter>;
|
|
37
37
|
export {};
|
package/esm/adapter.js
CHANGED
|
@@ -35,30 +35,33 @@ export const createSolanaWalletAdapter = async (options) => {
|
|
|
35
35
|
sendTransaction: async (sessionKey, instructions) => {
|
|
36
36
|
const rpc = createSolanaRpc(options.connection.rpcEndpoint);
|
|
37
37
|
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
38
|
-
|
|
39
|
-
const transaction = Array.isArray(instructions)
|
|
40
|
-
? await partiallySignTransactionMessageWithSigners(pipe(createTransactionMessage({ version: 0 }), (tx) => setTransactionMessageFeePayer(fromLegacyPublicKey(sponsor), tx), (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) => appendTransactionMessageInstructions(instructions.map((instruction) => instruction instanceof TransactionInstruction
|
|
41
|
-
? fromLegacyTransactionInstruction(instruction)
|
|
42
|
-
: instruction), tx), (tx) => compressTransactionMessageUsingAddressLookupTables(tx, Object.fromEntries(addressLookupTables?.map((table) => [
|
|
43
|
-
fromLegacyPublicKey(table.key),
|
|
44
|
-
table.state.addresses.map((address) => fromLegacyPublicKey(address)),
|
|
45
|
-
]) ?? [])), (tx) => addSignersToTransactionMessage([sessionKeySigner], tx)))
|
|
46
|
-
: await partiallySignTransaction([sessionKey], instructions instanceof VersionedTransaction
|
|
47
|
-
? fromVersionedTransaction(instructions)
|
|
48
|
-
: instructions);
|
|
49
|
-
const signature = await sendToPaymaster(options, transaction);
|
|
50
|
-
const lastValidBlockHeight = await rpc.getSlot().send();
|
|
51
|
-
const confirmationResult = await options.connection.confirmTransaction({
|
|
52
|
-
signature,
|
|
53
|
-
blockhash: latestBlockhash.blockhash.toString(),
|
|
54
|
-
lastValidBlockHeight: Number(lastValidBlockHeight),
|
|
55
|
-
});
|
|
56
|
-
return confirmationResult.value.err === null
|
|
57
|
-
? TransactionResult.Success(signature)
|
|
58
|
-
: TransactionResult.Failed(signature, confirmationResult.value.err);
|
|
38
|
+
return await sendToPaymaster(options, await buildTransaction(latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables));
|
|
59
39
|
},
|
|
60
40
|
};
|
|
61
41
|
};
|
|
42
|
+
const buildTransaction = async (latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables) => {
|
|
43
|
+
const sessionKeySigner = sessionKey
|
|
44
|
+
? await createSignerFromKeyPair(sessionKey)
|
|
45
|
+
: undefined;
|
|
46
|
+
if (Array.isArray(instructions)) {
|
|
47
|
+
return partiallySignTransactionMessageWithSigners(pipe(createTransactionMessage({ version: 0 }), (tx) => setTransactionMessageFeePayer(fromLegacyPublicKey(sponsor), tx), (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) => appendTransactionMessageInstructions(instructions.map((instruction) => instruction instanceof TransactionInstruction
|
|
48
|
+
? fromLegacyTransactionInstruction(instruction)
|
|
49
|
+
: instruction), tx), (tx) => compressTransactionMessageUsingAddressLookupTables(tx, Object.fromEntries(addressLookupTables?.map((table) => [
|
|
50
|
+
fromLegacyPublicKey(table.key),
|
|
51
|
+
table.state.addresses.map((address) => fromLegacyPublicKey(address)),
|
|
52
|
+
]) ?? [])), (tx) => sessionKeySigner === undefined
|
|
53
|
+
? tx
|
|
54
|
+
: addSignersToTransactionMessage([sessionKeySigner], tx)));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const tx = instructions instanceof VersionedTransaction
|
|
58
|
+
? fromVersionedTransaction(instructions)
|
|
59
|
+
: instructions;
|
|
60
|
+
return sessionKey === undefined
|
|
61
|
+
? tx
|
|
62
|
+
: partiallySignTransaction([sessionKey], tx);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
62
65
|
const getSponsor = async (options) => {
|
|
63
66
|
if ("sponsor" in options) {
|
|
64
67
|
return options.sponsor;
|
|
@@ -68,12 +71,29 @@ const getSponsor = async (options) => {
|
|
|
68
71
|
return new PublicKey(z.string().parse(await response.text()));
|
|
69
72
|
}
|
|
70
73
|
};
|
|
74
|
+
const sponsorAndSendResponseSchema = z
|
|
75
|
+
.discriminatedUnion("type", [
|
|
76
|
+
z.object({
|
|
77
|
+
type: z.literal("success"),
|
|
78
|
+
signature: z.string(),
|
|
79
|
+
}),
|
|
80
|
+
z.object({
|
|
81
|
+
type: z.literal("failed"),
|
|
82
|
+
signature: z.string(),
|
|
83
|
+
error: z.object({}),
|
|
84
|
+
}),
|
|
85
|
+
])
|
|
86
|
+
.transform((data) => {
|
|
87
|
+
return data.type === "success"
|
|
88
|
+
? TransactionResult.Success(data.signature)
|
|
89
|
+
: TransactionResult.Failed(data.signature, data.error);
|
|
90
|
+
});
|
|
71
91
|
const sendToPaymaster = async (options, transaction) => {
|
|
72
92
|
if ("sendToPaymaster" in options) {
|
|
73
93
|
return options.sendToPaymaster(transaction);
|
|
74
94
|
}
|
|
75
95
|
else {
|
|
76
|
-
const response = await fetch(new URL("/api/sponsor_and_send", options.paymaster ?? DEFAULT_PAYMASTER), {
|
|
96
|
+
const response = await fetch(new URL("/api/sponsor_and_send?confirm=true", options.paymaster ?? DEFAULT_PAYMASTER), {
|
|
77
97
|
method: "POST",
|
|
78
98
|
headers: {
|
|
79
99
|
"Content-Type": "application/json",
|
|
@@ -83,7 +103,7 @@ const sendToPaymaster = async (options, transaction) => {
|
|
|
83
103
|
}),
|
|
84
104
|
});
|
|
85
105
|
if (response.status === 200) {
|
|
86
|
-
return response.
|
|
106
|
+
return sponsorAndSendResponseSchema.parse(await response.json());
|
|
87
107
|
}
|
|
88
108
|
else {
|
|
89
109
|
throw new PaymasterResponseError(response.status, await response.text());
|
package/esm/index.d.ts
CHANGED
|
@@ -290,3 +290,12 @@ export type Session = {
|
|
|
290
290
|
sendTransaction: (instructions: Parameters<SessionAdapter["sendTransaction"]>[1]) => Promise<TransactionResult>;
|
|
291
291
|
sessionInfo: z.infer<typeof sessionInfoSchema>;
|
|
292
292
|
};
|
|
293
|
+
type SendTransferOptions = {
|
|
294
|
+
adapter: SessionAdapter;
|
|
295
|
+
walletPublicKey: PublicKey;
|
|
296
|
+
signMessage: (message: Uint8Array) => Promise<Uint8Array>;
|
|
297
|
+
mint: PublicKey;
|
|
298
|
+
amount: bigint;
|
|
299
|
+
recipient: PublicKey;
|
|
300
|
+
};
|
|
301
|
+
export declare const sendTransfer: (options: SendTransferOptions) => Promise<TransactionResult>;
|
package/esm/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { AnchorProvider, BorshAccountsCoder } from "@coral-xyz/anchor";
|
|
2
|
-
import { DomainRegistryIdl, SessionManagerProgram, SessionManagerIdl, } from "@fogo/sessions-idls";
|
|
2
|
+
import { DomainRegistryIdl, SessionManagerProgram, SessionManagerIdl, IntentTransferProgram, } from "@fogo/sessions-idls";
|
|
3
3
|
import { findMetadataPda, safeFetchMetadata, } from "@metaplex-foundation/mpl-token-metadata";
|
|
4
4
|
import { publicKey as metaplexPublicKey } from "@metaplex-foundation/umi";
|
|
5
5
|
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
|
|
6
6
|
import { sha256 } from "@noble/hashes/sha2";
|
|
7
|
-
import {
|
|
7
|
+
import { fromLegacyPublicKey } from "@solana/compat";
|
|
8
|
+
import { generateKeyPair, getAddressFromPublicKey, getProgramDerivedAddress, } from "@solana/kit";
|
|
8
9
|
import { createAssociatedTokenAccountIdempotentInstruction, getAssociatedTokenAddressSync, getMint, } from "@solana/spl-token";
|
|
9
10
|
import { Ed25519Program, PublicKey } from "@solana/web3.js";
|
|
10
11
|
import BN from "bn.js";
|
|
@@ -18,6 +19,8 @@ const UNLIMITED_TOKEN_PERMISSIONS_VALUE = "this app may spend any amount of any
|
|
|
18
19
|
const TOKENLESS_PERMISSIONS_VALUE = "this app may not spend any tokens";
|
|
19
20
|
const CURRENT_MAJOR = "0";
|
|
20
21
|
const CURRENT_MINOR = "1";
|
|
22
|
+
const CURRENT_INTENT_TRANSFER_MAJOR = "0";
|
|
23
|
+
const CURRENT_INTENT_TRANSFER_MINOR = "1";
|
|
21
24
|
export const establishSession = async (options) => {
|
|
22
25
|
const sessionKey = await generateKeyPair();
|
|
23
26
|
if (options.unlimited) {
|
|
@@ -143,10 +146,11 @@ export var AuthorizedTokens;
|
|
|
143
146
|
AuthorizedTokens[AuthorizedTokens["All"] = 0] = "All";
|
|
144
147
|
AuthorizedTokens[AuthorizedTokens["Specific"] = 1] = "Specific";
|
|
145
148
|
})(AuthorizedTokens || (AuthorizedTokens = {}));
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
149
|
+
var SymbolOrMintType;
|
|
150
|
+
(function (SymbolOrMintType) {
|
|
151
|
+
SymbolOrMintType[SymbolOrMintType["Symbol"] = 0] = "Symbol";
|
|
152
|
+
SymbolOrMintType[SymbolOrMintType["Mint"] = 1] = "Mint";
|
|
153
|
+
})(SymbolOrMintType || (SymbolOrMintType = {}));
|
|
150
154
|
const SymbolOrMint = {
|
|
151
155
|
Symbol: (symbol) => ({
|
|
152
156
|
type: SymbolOrMintType.Symbol,
|
|
@@ -290,3 +294,61 @@ const EstablishSessionResult = {
|
|
|
290
294
|
error,
|
|
291
295
|
}),
|
|
292
296
|
};
|
|
297
|
+
const TRANSFER_MESSAGE_HEADER = `Fogo Transfer:
|
|
298
|
+
Signing this intent will transfer the tokens as described below.
|
|
299
|
+
`;
|
|
300
|
+
export const sendTransfer = async (options) => {
|
|
301
|
+
const sourceAta = getAssociatedTokenAddressSync(options.mint, options.walletPublicKey);
|
|
302
|
+
const destinationAta = getAssociatedTokenAddressSync(options.mint, options.recipient);
|
|
303
|
+
const program = new IntentTransferProgram(new AnchorProvider(options.adapter.connection, {}, {}));
|
|
304
|
+
const umi = createUmi(options.adapter.connection.rpcEndpoint);
|
|
305
|
+
const metaplexMint = metaplexPublicKey(options.mint.toBase58());
|
|
306
|
+
const metadataAddress = findMetadataPda(umi, { mint: metaplexMint })[0];
|
|
307
|
+
const metadata = await safeFetchMetadata(umi, metadataAddress);
|
|
308
|
+
const symbol = metadata?.symbol ?? undefined;
|
|
309
|
+
return options.adapter.sendTransaction(undefined, [
|
|
310
|
+
createAssociatedTokenAccountIdempotentInstruction(options.adapter.payer, destinationAta, options.recipient, options.mint),
|
|
311
|
+
await buildTransferIntentInstruction(program, options, symbol),
|
|
312
|
+
await program.methods
|
|
313
|
+
.sendTokens()
|
|
314
|
+
.accounts({
|
|
315
|
+
destination: destinationAta,
|
|
316
|
+
mint: options.mint,
|
|
317
|
+
source: sourceAta,
|
|
318
|
+
sponsor: options.adapter.payer,
|
|
319
|
+
// eslint-disable-next-line unicorn/no-null
|
|
320
|
+
metadata: symbol === undefined ? null : new PublicKey(metadataAddress),
|
|
321
|
+
})
|
|
322
|
+
.instruction(),
|
|
323
|
+
]);
|
|
324
|
+
};
|
|
325
|
+
const buildTransferIntentInstruction = async (program, options, symbol) => {
|
|
326
|
+
const [nonce, { decimals }] = await Promise.all([
|
|
327
|
+
getNonce(program, options.walletPublicKey),
|
|
328
|
+
getMint(options.adapter.connection, options.mint),
|
|
329
|
+
]);
|
|
330
|
+
const message = new TextEncoder().encode([
|
|
331
|
+
TRANSFER_MESSAGE_HEADER,
|
|
332
|
+
serializeKV({
|
|
333
|
+
version: `${CURRENT_INTENT_TRANSFER_MAJOR}.${CURRENT_INTENT_TRANSFER_MINOR}`,
|
|
334
|
+
chain_id: options.adapter.chainId,
|
|
335
|
+
token: symbol ?? options.mint.toBase58(),
|
|
336
|
+
amount: amountToString(options.amount, decimals),
|
|
337
|
+
recipient: options.recipient.toBase58(),
|
|
338
|
+
nonce: nonce === null ? "1" : nonce.nonce.add(new BN(1)).toString(),
|
|
339
|
+
}),
|
|
340
|
+
].join("\n"));
|
|
341
|
+
const intentSignature = await options.signMessage(message);
|
|
342
|
+
return Ed25519Program.createInstructionWithPublicKey({
|
|
343
|
+
publicKey: options.walletPublicKey.toBytes(),
|
|
344
|
+
signature: intentSignature,
|
|
345
|
+
message: message,
|
|
346
|
+
});
|
|
347
|
+
};
|
|
348
|
+
const getNonce = async (program, walletPublicKey) => {
|
|
349
|
+
const [noncePda] = await getProgramDerivedAddress({
|
|
350
|
+
programAddress: fromLegacyPublicKey(program.programId),
|
|
351
|
+
seeds: [Buffer.from("nonce"), walletPublicKey.toBuffer()],
|
|
352
|
+
});
|
|
353
|
+
return program.account.nonce.fetchNullable(noncePda);
|
|
354
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fogo/sessions-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "A set of utilities for integrating with Fogo sessions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fogo",
|
|
@@ -48,6 +48,6 @@
|
|
|
48
48
|
"bn.js": "^5.1.2",
|
|
49
49
|
"bs58": "^6.0.0",
|
|
50
50
|
"zod": "^3.25.62",
|
|
51
|
-
"@fogo/sessions-idls": "^0.0.
|
|
51
|
+
"@fogo/sessions-idls": "^0.0.4"
|
|
52
52
|
}
|
|
53
53
|
}
|