@fogo/sessions-sdk 0.0.12 → 0.0.14
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.js +6 -2
- package/cjs/crypto.d.ts +21 -0
- package/cjs/crypto.js +39 -0
- package/cjs/index.d.ts +1203 -158
- package/cjs/index.js +262 -46
- package/esm/adapter.js +6 -2
- package/esm/crypto.d.ts +21 -0
- package/esm/crypto.js +30 -0
- package/esm/index.d.ts +1203 -158
- package/esm/index.js +260 -47
- package/package.json +3 -12
- package/cjs/paymaster.d.ts +0 -7
- package/cjs/paymaster.js +0 -51
- package/esm/paymaster.d.ts +0 -7
- package/esm/paymaster.js +0 -47
package/esm/index.js
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
import { AnchorProvider, BorshAccountsCoder } from "@coral-xyz/anchor";
|
|
2
|
-
import { DomainRegistryIdl,
|
|
2
|
+
import { DomainRegistryIdl, IntentTransferProgram, SessionManagerIdl, SessionManagerProgram, } 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
7
|
import { fromLegacyPublicKey } from "@solana/compat";
|
|
8
|
-
import { generateKeyPair, getAddressFromPublicKey, getProgramDerivedAddress, } from "@solana/kit";
|
|
8
|
+
import { generateKeyPair, getAddressFromPublicKey, getProgramDerivedAddress, verifySignature, } from "@solana/kit";
|
|
9
9
|
import { createAssociatedTokenAccountIdempotentInstruction, getAssociatedTokenAddressSync, getMint, } from "@solana/spl-token";
|
|
10
10
|
import { Ed25519Program, PublicKey } from "@solana/web3.js";
|
|
11
11
|
import BN from "bn.js";
|
|
12
|
+
import bs58 from "bs58";
|
|
12
13
|
import { z } from "zod";
|
|
13
14
|
import { TransactionResultType } from "./adapter.js";
|
|
14
|
-
|
|
15
|
+
import { importKey, signMessageWithKey, verifyMessageWithKey, } from "./crypto.js";
|
|
16
|
+
export { createSolanaWalletAdapter, TransactionResultType, } from "./adapter.js";
|
|
15
17
|
const MESSAGE_HEADER = `Fogo Sessions:
|
|
16
18
|
Signing this intent will allow this app to interact with your on-chain balances. Please make sure you trust this app and the domain in the message matches the domain of the current web application.
|
|
17
19
|
`;
|
|
18
20
|
const UNLIMITED_TOKEN_PERMISSIONS_VALUE = "this app may spend any amount of any token";
|
|
19
21
|
const TOKENLESS_PERMISSIONS_VALUE = "this app may not spend any tokens";
|
|
20
22
|
const CURRENT_MAJOR = "0";
|
|
21
|
-
const CURRENT_MINOR = "
|
|
23
|
+
const CURRENT_MINOR = "3";
|
|
22
24
|
const CURRENT_INTENT_TRANSFER_MAJOR = "0";
|
|
23
25
|
const CURRENT_INTENT_TRANSFER_MINOR = "1";
|
|
24
26
|
export const establishSession = async (options) => {
|
|
25
|
-
const sessionKey =
|
|
27
|
+
const sessionKey = options.createUnsafeExtractableSessionKey
|
|
28
|
+
? await crypto.subtle.generateKey("Ed25519", true, ["sign", "verify"])
|
|
29
|
+
: await generateKeyPair();
|
|
26
30
|
if (options.unlimited) {
|
|
27
31
|
return sendSessionEstablishTransaction(options, sessionKey, await Promise.all([
|
|
28
32
|
buildIntentInstruction(options, sessionKey),
|
|
@@ -63,9 +67,26 @@ export const replaceSession = async (options) => establishSession({
|
|
|
63
67
|
...options,
|
|
64
68
|
walletPublicKey: options.session.walletPublicKey,
|
|
65
69
|
});
|
|
70
|
+
export const revokeSession = async (options) => {
|
|
71
|
+
if (options.session.sessionInfo.minor >= 2) {
|
|
72
|
+
const instruction = await new SessionManagerProgram(new AnchorProvider(options.adapter.connection, {}, {})).methods
|
|
73
|
+
.revokeSession()
|
|
74
|
+
.accounts({
|
|
75
|
+
sponsor: options.session.sessionInfo.sponsor,
|
|
76
|
+
session: options.session.sessionPublicKey,
|
|
77
|
+
})
|
|
78
|
+
.instruction();
|
|
79
|
+
return options.adapter.sendTransaction(options.session.sessionKey, [
|
|
80
|
+
instruction,
|
|
81
|
+
]);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
66
87
|
export const reestablishSession = async (adapter, walletPublicKey, sessionKey) => createSession(adapter, walletPublicKey, sessionKey);
|
|
67
88
|
export const getSessionAccount = async (connection, sessionPublicKey) => {
|
|
68
|
-
const result = await connection.getAccountInfo(sessionPublicKey);
|
|
89
|
+
const result = await connection.getAccountInfo(sessionPublicKey, "confirmed");
|
|
69
90
|
return result === null
|
|
70
91
|
? undefined
|
|
71
92
|
: sessionInfoSchema.parse(new BorshAccountsCoder(SessionManagerIdl).decode("Session", result.data));
|
|
@@ -86,49 +107,153 @@ const createSession = async (adapter, walletPublicKey, sessionKey) => {
|
|
|
86
107
|
};
|
|
87
108
|
const sessionInfoSchema = z
|
|
88
109
|
.object({
|
|
89
|
-
session_info: z.
|
|
90
|
-
|
|
91
|
-
z.object({
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
110
|
+
session_info: z.union([
|
|
111
|
+
z.object({
|
|
112
|
+
V1: z.object({
|
|
113
|
+
"0": z.object({
|
|
114
|
+
authorized_programs: z.union([
|
|
115
|
+
z.object({
|
|
116
|
+
Specific: z.object({
|
|
117
|
+
0: z.array(z.object({
|
|
118
|
+
program_id: z.instanceof(PublicKey),
|
|
119
|
+
signer_pda: z.instanceof(PublicKey),
|
|
120
|
+
})),
|
|
121
|
+
}),
|
|
122
|
+
}),
|
|
123
|
+
z.object({
|
|
124
|
+
All: z.object({}),
|
|
125
|
+
}),
|
|
126
|
+
]),
|
|
127
|
+
authorized_tokens: z.union([
|
|
128
|
+
z.object({ Specific: z.object({}) }),
|
|
129
|
+
z.object({ All: z.object({}) }),
|
|
130
|
+
]),
|
|
131
|
+
expiration: z.instanceof(BN),
|
|
132
|
+
extra: z.object({
|
|
133
|
+
0: z.unknown(),
|
|
134
|
+
}),
|
|
135
|
+
user: z.instanceof(PublicKey),
|
|
97
136
|
}),
|
|
98
137
|
}),
|
|
99
|
-
|
|
100
|
-
|
|
138
|
+
}),
|
|
139
|
+
z.object({
|
|
140
|
+
V2: z.object({
|
|
141
|
+
"0": z.union([
|
|
142
|
+
z.object({
|
|
143
|
+
Revoked: z.instanceof(BN),
|
|
144
|
+
}),
|
|
145
|
+
z.object({
|
|
146
|
+
Active: z.object({
|
|
147
|
+
"0": z.object({
|
|
148
|
+
authorized_programs: z.union([
|
|
149
|
+
z.object({
|
|
150
|
+
Specific: z.object({
|
|
151
|
+
0: z.array(z.object({
|
|
152
|
+
program_id: z.instanceof(PublicKey),
|
|
153
|
+
signer_pda: z.instanceof(PublicKey),
|
|
154
|
+
})),
|
|
155
|
+
}),
|
|
156
|
+
}),
|
|
157
|
+
z.object({
|
|
158
|
+
All: z.object({}),
|
|
159
|
+
}),
|
|
160
|
+
]),
|
|
161
|
+
authorized_tokens: z.union([
|
|
162
|
+
z.object({ Specific: z.object({}) }),
|
|
163
|
+
z.object({ All: z.object({}) }),
|
|
164
|
+
]),
|
|
165
|
+
expiration: z.instanceof(BN),
|
|
166
|
+
extra: z.object({
|
|
167
|
+
0: z.unknown(),
|
|
168
|
+
}),
|
|
169
|
+
user: z.instanceof(PublicKey),
|
|
170
|
+
}),
|
|
171
|
+
}),
|
|
172
|
+
}),
|
|
173
|
+
]),
|
|
101
174
|
}),
|
|
102
|
-
]),
|
|
103
|
-
authorized_tokens: z.union([
|
|
104
|
-
z.object({ Specific: z.object({}) }),
|
|
105
|
-
z.object({ All: z.object({}) }),
|
|
106
|
-
]),
|
|
107
|
-
expiration: z.instanceof(BN),
|
|
108
|
-
extra: z.object({
|
|
109
|
-
0: z.unknown(),
|
|
110
175
|
}),
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
176
|
+
z.object({
|
|
177
|
+
V3: z.object({
|
|
178
|
+
"0": z.union([
|
|
179
|
+
z.object({
|
|
180
|
+
Revoked: z.instanceof(BN),
|
|
181
|
+
}),
|
|
182
|
+
z.object({
|
|
183
|
+
Active: z.object({
|
|
184
|
+
"0": z.object({
|
|
185
|
+
authorized_programs: z.union([
|
|
186
|
+
z.object({
|
|
187
|
+
Specific: z.object({
|
|
188
|
+
0: z.array(z.object({
|
|
189
|
+
program_id: z.instanceof(PublicKey),
|
|
190
|
+
signer_pda: z.instanceof(PublicKey),
|
|
191
|
+
})),
|
|
192
|
+
}),
|
|
193
|
+
}),
|
|
194
|
+
z.object({
|
|
195
|
+
All: z.object({}),
|
|
196
|
+
}),
|
|
197
|
+
]),
|
|
198
|
+
authorized_tokens: z.union([
|
|
199
|
+
z.object({
|
|
200
|
+
Specific: z.object({
|
|
201
|
+
"0": z.array(z.instanceof(PublicKey)),
|
|
202
|
+
}),
|
|
203
|
+
}),
|
|
204
|
+
z.object({ All: z.object({}) }),
|
|
205
|
+
]),
|
|
206
|
+
expiration: z.instanceof(BN),
|
|
207
|
+
extra: z.object({
|
|
208
|
+
0: z.unknown(),
|
|
209
|
+
}),
|
|
210
|
+
user: z.instanceof(PublicKey),
|
|
211
|
+
}),
|
|
212
|
+
}),
|
|
213
|
+
}),
|
|
214
|
+
]),
|
|
215
|
+
}),
|
|
216
|
+
}),
|
|
217
|
+
]),
|
|
218
|
+
major: z.number(),
|
|
219
|
+
sponsor: z.instanceof(PublicKey),
|
|
115
220
|
})
|
|
116
|
-
.transform(({ session_info }) =>
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
221
|
+
.transform(({ session_info, major, sponsor }) => {
|
|
222
|
+
let activeSessionInfo;
|
|
223
|
+
let minor;
|
|
224
|
+
if ("V1" in session_info) {
|
|
225
|
+
activeSessionInfo = session_info.V1["0"];
|
|
226
|
+
minor = 1;
|
|
227
|
+
}
|
|
228
|
+
else if ("V2" in session_info && "Active" in session_info.V2["0"]) {
|
|
229
|
+
activeSessionInfo = session_info.V2["0"].Active["0"];
|
|
230
|
+
minor = 2;
|
|
231
|
+
}
|
|
232
|
+
else if ("V3" in session_info && "Active" in session_info.V3["0"]) {
|
|
233
|
+
activeSessionInfo = session_info.V3["0"].Active["0"];
|
|
234
|
+
minor = 3;
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
authorizedPrograms: "All" in activeSessionInfo.authorized_programs
|
|
241
|
+
? AuthorizedPrograms.All()
|
|
242
|
+
: AuthorizedPrograms.Specific(activeSessionInfo.authorized_programs.Specific[0].map(({ program_id, signer_pda }) => ({
|
|
243
|
+
programId: program_id,
|
|
244
|
+
signerPda: signer_pda,
|
|
245
|
+
}))),
|
|
246
|
+
authorizedTokens: "All" in activeSessionInfo.authorized_tokens
|
|
247
|
+
? AuthorizedTokens.All
|
|
248
|
+
: AuthorizedTokens.Specific,
|
|
249
|
+
expiration: new Date(Number(activeSessionInfo.expiration) * 1000),
|
|
250
|
+
extra: activeSessionInfo.extra[0],
|
|
251
|
+
major: major,
|
|
252
|
+
minor: minor,
|
|
253
|
+
user: activeSessionInfo.user,
|
|
254
|
+
sponsor,
|
|
255
|
+
};
|
|
256
|
+
});
|
|
132
257
|
export var AuthorizedProgramsType;
|
|
133
258
|
(function (AuthorizedProgramsType) {
|
|
134
259
|
AuthorizedProgramsType[AuthorizedProgramsType["All"] = 0] = "All";
|
|
@@ -181,6 +306,36 @@ const getTokenInfo = async (adapter, limits) => {
|
|
|
181
306
|
};
|
|
182
307
|
}));
|
|
183
308
|
};
|
|
309
|
+
const serializeU16LE = (value) => {
|
|
310
|
+
const result = new ArrayBuffer(2);
|
|
311
|
+
new DataView(result).setUint16(0, value, true); // littleEndian = true
|
|
312
|
+
return new Uint8Array(result);
|
|
313
|
+
};
|
|
314
|
+
// Some wallets add a prefix to the messag before signing, for example Ledger through Phantom
|
|
315
|
+
const addOffchainMessagePrefixToMessageIfNeeded = async (walletPublicKey, signature, message) => {
|
|
316
|
+
const publicKey = await crypto.subtle.importKey("raw", walletPublicKey.toBytes(), { name: "Ed25519" }, true, ["verify"]);
|
|
317
|
+
if (await verifySignature(publicKey, signature, message)) {
|
|
318
|
+
return message;
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
// Source: https://github.com/anza-xyz/solana-sdk/blob/master/offchain-message/src/lib.rs#L162
|
|
322
|
+
const messageWithOffchainMessagePrefix = Uint8Array.from([
|
|
323
|
+
// eslint-disable-next-line unicorn/number-literal-case
|
|
324
|
+
0xff,
|
|
325
|
+
...new TextEncoder().encode("solana offchain"),
|
|
326
|
+
0,
|
|
327
|
+
1,
|
|
328
|
+
...serializeU16LE(message.length),
|
|
329
|
+
...message,
|
|
330
|
+
]);
|
|
331
|
+
if (await verifySignature(publicKey, signature, messageWithOffchainMessagePrefix)) {
|
|
332
|
+
return messageWithOffchainMessagePrefix;
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
throw new Error("The signature provided by the browser wallet is not valid");
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
};
|
|
184
339
|
const buildIntentInstruction = async (options, sessionKey, tokens) => {
|
|
185
340
|
const message = await buildMessage({
|
|
186
341
|
chainId: options.adapter.chainId,
|
|
@@ -194,7 +349,7 @@ const buildIntentInstruction = async (options, sessionKey, tokens) => {
|
|
|
194
349
|
return Ed25519Program.createInstructionWithPublicKey({
|
|
195
350
|
publicKey: options.walletPublicKey.toBytes(),
|
|
196
351
|
signature: intentSignature,
|
|
197
|
-
message: message,
|
|
352
|
+
message: await addOffchainMessagePrefixToMessageIfNeeded(options.walletPublicKey, intentSignature, message),
|
|
198
353
|
});
|
|
199
354
|
};
|
|
200
355
|
const buildMessage = async (body) => new TextEncoder().encode([
|
|
@@ -206,9 +361,20 @@ const buildMessage = async (body) => new TextEncoder().encode([
|
|
|
206
361
|
expires: body.expires.toISOString(),
|
|
207
362
|
session_key: await getAddressFromPublicKey(body.sessionKey.publicKey),
|
|
208
363
|
tokens: serializeTokenList(body.tokens),
|
|
209
|
-
...(body.extra && { extra: body.extra }),
|
|
210
364
|
}),
|
|
365
|
+
body.extra && serializeExtra(body.extra),
|
|
211
366
|
].join("\n"));
|
|
367
|
+
const serializeExtra = (extra) => {
|
|
368
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
369
|
+
if (!/^[a-z]+(_[a-z0-9]+)*$/.test(key)) {
|
|
370
|
+
throw new Error(`Extra key must be a snake_case string: ${key}`);
|
|
371
|
+
}
|
|
372
|
+
if (value.includes("\n")) {
|
|
373
|
+
throw new Error(`Extra value must not contain a line break: ${value}`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return serializeKV(extra);
|
|
377
|
+
};
|
|
212
378
|
const serializeKV = (data) => Object.entries(data)
|
|
213
379
|
.map(([key, value]) => [key, ":", value.startsWith("\n") ? "" : " ", value].join(""))
|
|
214
380
|
.join("\n");
|
|
@@ -342,7 +508,7 @@ const buildTransferIntentInstruction = async (program, options, symbol) => {
|
|
|
342
508
|
return Ed25519Program.createInstructionWithPublicKey({
|
|
343
509
|
publicKey: options.walletPublicKey.toBytes(),
|
|
344
510
|
signature: intentSignature,
|
|
345
|
-
message: message,
|
|
511
|
+
message: await addOffchainMessagePrefixToMessageIfNeeded(options.walletPublicKey, intentSignature, message),
|
|
346
512
|
});
|
|
347
513
|
};
|
|
348
514
|
const getNonce = async (program, walletPublicKey) => {
|
|
@@ -352,3 +518,50 @@ const getNonce = async (program, walletPublicKey) => {
|
|
|
352
518
|
});
|
|
353
519
|
return program.account.nonce.fetchNullable(noncePda);
|
|
354
520
|
};
|
|
521
|
+
const loginTokenPayloadSchema = z.object({
|
|
522
|
+
iat: z.number(),
|
|
523
|
+
sessionPublicKey: z.string(),
|
|
524
|
+
});
|
|
525
|
+
/**
|
|
526
|
+
* Create a login token signed with the session key
|
|
527
|
+
* @param session - The session to create a login token for
|
|
528
|
+
* @returns The login token
|
|
529
|
+
*/
|
|
530
|
+
export const createLogInToken = async (session) => {
|
|
531
|
+
const payload = {
|
|
532
|
+
// ...we can pass any arbitrary data we want to sign here...
|
|
533
|
+
iat: Date.now(),
|
|
534
|
+
sessionPublicKey: session.sessionPublicKey.toBase58(),
|
|
535
|
+
};
|
|
536
|
+
const message = JSON.stringify(payload);
|
|
537
|
+
// Sign the payload with the session private key
|
|
538
|
+
const signature = await signMessageWithKey(session.sessionKey, message);
|
|
539
|
+
// Return base58(message) + base58(signature)
|
|
540
|
+
return `${bs58.encode(new TextEncoder().encode(message))}.${signature}`;
|
|
541
|
+
};
|
|
542
|
+
/**
|
|
543
|
+
* Verify a login token
|
|
544
|
+
* @param token - The login token to verify against the session public key
|
|
545
|
+
* @param connection - The connection to use to get the session account
|
|
546
|
+
* @returns The session account if the token is valid, otherwise undefined
|
|
547
|
+
*/
|
|
548
|
+
export const verifyLogInToken = async (token, connection) => {
|
|
549
|
+
const [rawMessage, signature] = token.split(".");
|
|
550
|
+
if (!rawMessage || !signature)
|
|
551
|
+
return;
|
|
552
|
+
// Decode + parse payload
|
|
553
|
+
const messageStr = new TextDecoder().decode(bs58.decode(rawMessage));
|
|
554
|
+
const payload = loginTokenPayloadSchema.parse(JSON.parse(messageStr));
|
|
555
|
+
// Verify signature with sessionPublicKey
|
|
556
|
+
const sessionCryptoKey = await importKey(payload.sessionPublicKey);
|
|
557
|
+
const isValid = await verifyMessageWithKey(sessionCryptoKey, messageStr, signature);
|
|
558
|
+
if (!isValid)
|
|
559
|
+
return;
|
|
560
|
+
const sessionAccount = await getSessionAccount(connection, new PublicKey(payload.sessionPublicKey));
|
|
561
|
+
if (!sessionAccount)
|
|
562
|
+
return;
|
|
563
|
+
if (sessionAccount.expiration.getTime() < Date.now()) {
|
|
564
|
+
throw new Error("The session associated with this login token has expired");
|
|
565
|
+
}
|
|
566
|
+
return sessionAccount;
|
|
567
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fogo/sessions-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "A set of utilities for integrating with Fogo sessions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fogo",
|
|
@@ -24,16 +24,6 @@
|
|
|
24
24
|
"types": "./cjs/index.d.ts",
|
|
25
25
|
"default": "./cjs/index.js"
|
|
26
26
|
}
|
|
27
|
-
},
|
|
28
|
-
"./paymaster": {
|
|
29
|
-
"import": {
|
|
30
|
-
"types": "./esm/paymaster.d.ts",
|
|
31
|
-
"default": "./esm/paymaster.js"
|
|
32
|
-
},
|
|
33
|
-
"require": {
|
|
34
|
-
"types": "./cjs/paymaster.d.ts",
|
|
35
|
-
"default": "./cjs/paymaster.js"
|
|
36
|
-
}
|
|
37
27
|
}
|
|
38
28
|
},
|
|
39
29
|
"dependencies": {
|
|
@@ -41,6 +31,7 @@
|
|
|
41
31
|
"@metaplex-foundation/mpl-token-metadata": "^3.4.0",
|
|
42
32
|
"@metaplex-foundation/umi": "^1.2.0",
|
|
43
33
|
"@metaplex-foundation/umi-bundle-defaults": "^1.2.0",
|
|
34
|
+
"@noble/hashes": "^1.8.0",
|
|
44
35
|
"@solana/compat": "^2.1.1",
|
|
45
36
|
"@solana/kit": "^2.1.1",
|
|
46
37
|
"@solana/spl-token": "^0.4.13",
|
|
@@ -48,6 +39,6 @@
|
|
|
48
39
|
"bn.js": "^5.1.2",
|
|
49
40
|
"bs58": "^6.0.0",
|
|
50
41
|
"zod": "^3.25.62",
|
|
51
|
-
"@fogo/sessions-idls": "^0.0.
|
|
42
|
+
"@fogo/sessions-idls": "^0.0.5"
|
|
52
43
|
}
|
|
53
44
|
}
|
package/cjs/paymaster.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Transaction, Rpc, SolanaRpcApi } from "@solana/kit";
|
|
2
|
-
import { Keypair } from "@solana/web3.js";
|
|
3
|
-
export declare const sponsorAndSend: (rpc: Rpc<SolanaRpcApi>, sponsor: CryptoKeyPair, transaction: Transaction) => Promise<import("@solana/kit").Signature>;
|
|
4
|
-
export declare const createPaymasterEndpoint: (options: {
|
|
5
|
-
rpc: string;
|
|
6
|
-
sponsor: Keypair;
|
|
7
|
-
}) => Promise<(req: Request) => Promise<Response>>;
|
package/cjs/paymaster.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createPaymasterEndpoint = exports.sponsorAndSend = void 0;
|
|
4
|
-
const compat_1 = require("@solana/compat");
|
|
5
|
-
const kit_1 = require("@solana/kit");
|
|
6
|
-
const zod_1 = require("zod");
|
|
7
|
-
const sponsorAndSend = async (rpc, sponsor, transaction) => rpc
|
|
8
|
-
.sendTransaction((0, kit_1.getBase64EncodedWireTransaction)(await (0, kit_1.signTransaction)([sponsor], transaction)), {
|
|
9
|
-
encoding: "base64",
|
|
10
|
-
skipPreflight: true,
|
|
11
|
-
})
|
|
12
|
-
.send();
|
|
13
|
-
exports.sponsorAndSend = sponsorAndSend;
|
|
14
|
-
const createPaymasterEndpoint = async (options) => {
|
|
15
|
-
const rpc = (0, kit_1.createSolanaRpc)(options.rpc);
|
|
16
|
-
const sponsor = await (0, compat_1.fromLegacyKeypair)(options.sponsor);
|
|
17
|
-
return async (req) => {
|
|
18
|
-
const data = postBodySchema.parse(await req.json());
|
|
19
|
-
try {
|
|
20
|
-
const transaction = (0, kit_1.getTransactionDecoder)().decode((0, kit_1.getBase64Encoder)().encode(data.transaction));
|
|
21
|
-
try {
|
|
22
|
-
return new Response(await (0, exports.sponsorAndSend)(rpc, sponsor, transaction));
|
|
23
|
-
}
|
|
24
|
-
catch (error) {
|
|
25
|
-
// eslint-disable-next-line no-console
|
|
26
|
-
console.error(error);
|
|
27
|
-
return new Response(`Failed to sponsor and send: ${serializeError(error)}`, { status: 500 });
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
// eslint-disable-next-line no-console
|
|
32
|
-
console.error(error);
|
|
33
|
-
return new Response("Failed to deserialize transaction", { status: 400 });
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
};
|
|
37
|
-
exports.createPaymasterEndpoint = createPaymasterEndpoint;
|
|
38
|
-
const postBodySchema = zod_1.z.strictObject({
|
|
39
|
-
transaction: zod_1.z.string(),
|
|
40
|
-
});
|
|
41
|
-
const serializeError = (error) => {
|
|
42
|
-
if (error instanceof Error) {
|
|
43
|
-
return error.message;
|
|
44
|
-
}
|
|
45
|
-
else if (typeof error === "string") {
|
|
46
|
-
return error.toString();
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
return "Unknown Error";
|
|
50
|
-
}
|
|
51
|
-
};
|
package/esm/paymaster.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Transaction, Rpc, SolanaRpcApi } from "@solana/kit";
|
|
2
|
-
import { Keypair } from "@solana/web3.js";
|
|
3
|
-
export declare const sponsorAndSend: (rpc: Rpc<SolanaRpcApi>, sponsor: CryptoKeyPair, transaction: Transaction) => Promise<import("@solana/kit").Signature>;
|
|
4
|
-
export declare const createPaymasterEndpoint: (options: {
|
|
5
|
-
rpc: string;
|
|
6
|
-
sponsor: Keypair;
|
|
7
|
-
}) => Promise<(req: Request) => Promise<Response>>;
|
package/esm/paymaster.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { fromLegacyKeypair } from "@solana/compat";
|
|
2
|
-
import { signTransaction, createSolanaRpc, getBase64EncodedWireTransaction, getTransactionDecoder, getBase64Encoder, } from "@solana/kit";
|
|
3
|
-
import { Keypair } from "@solana/web3.js";
|
|
4
|
-
import { z } from "zod";
|
|
5
|
-
export const sponsorAndSend = async (rpc, sponsor, transaction) => rpc
|
|
6
|
-
.sendTransaction(getBase64EncodedWireTransaction(await signTransaction([sponsor], transaction)), {
|
|
7
|
-
encoding: "base64",
|
|
8
|
-
skipPreflight: true,
|
|
9
|
-
})
|
|
10
|
-
.send();
|
|
11
|
-
export const createPaymasterEndpoint = async (options) => {
|
|
12
|
-
const rpc = createSolanaRpc(options.rpc);
|
|
13
|
-
const sponsor = await fromLegacyKeypair(options.sponsor);
|
|
14
|
-
return async (req) => {
|
|
15
|
-
const data = postBodySchema.parse(await req.json());
|
|
16
|
-
try {
|
|
17
|
-
const transaction = getTransactionDecoder().decode(getBase64Encoder().encode(data.transaction));
|
|
18
|
-
try {
|
|
19
|
-
return new Response(await sponsorAndSend(rpc, sponsor, transaction));
|
|
20
|
-
}
|
|
21
|
-
catch (error) {
|
|
22
|
-
// eslint-disable-next-line no-console
|
|
23
|
-
console.error(error);
|
|
24
|
-
return new Response(`Failed to sponsor and send: ${serializeError(error)}`, { status: 500 });
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
// eslint-disable-next-line no-console
|
|
29
|
-
console.error(error);
|
|
30
|
-
return new Response("Failed to deserialize transaction", { status: 400 });
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
const postBodySchema = z.strictObject({
|
|
35
|
-
transaction: z.string(),
|
|
36
|
-
});
|
|
37
|
-
const serializeError = (error) => {
|
|
38
|
-
if (error instanceof Error) {
|
|
39
|
-
return error.message;
|
|
40
|
-
}
|
|
41
|
-
else if (typeof error === "string") {
|
|
42
|
-
return error.toString();
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
return "Unknown Error";
|
|
46
|
-
}
|
|
47
|
-
};
|