@fogo/sessions-sdk 0.1.4 → 0.1.6
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/connection.js +17 -48
- package/cjs/index.d.ts +5 -4
- package/cjs/index.js +32 -3
- package/cjs/instructions.d.ts +14 -2
- package/cjs/instructions.js +26 -0
- package/cjs/paymaster.d.ts +9 -0
- package/cjs/paymaster.js +31 -0
- package/esm/connection.js +16 -47
- package/esm/index.d.ts +5 -4
- package/esm/index.js +30 -3
- package/esm/instructions.d.ts +14 -2
- package/esm/instructions.js +25 -1
- package/esm/paymaster.d.ts +9 -0
- package/esm/paymaster.js +23 -0
- package/package.json +1 -1
package/cjs/connection.js
CHANGED
|
@@ -4,17 +4,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createSessionConnection = exports.TransactionResultType = void 0;
|
|
7
|
-
const anchor_1 = require("@coral-xyz/anchor");
|
|
8
7
|
const sessions_idls_1 = require("@fogo/sessions-idls");
|
|
9
|
-
const sha2_1 = require("@noble/hashes/sha2");
|
|
10
8
|
const compat_1 = require("@solana/compat");
|
|
11
9
|
const kit_1 = require("@solana/kit");
|
|
12
|
-
const spl_token_1 = require("@solana/spl-token");
|
|
13
10
|
const web3_js_1 = require("@solana/web3.js");
|
|
14
11
|
const bn_js_1 = __importDefault(require("bn.js"));
|
|
15
12
|
const zod_1 = require("zod");
|
|
13
|
+
const instructions_js_1 = require("./instructions.js");
|
|
16
14
|
const mints_js_1 = require("./mints.js");
|
|
17
15
|
const network_js_1 = require("./network.js");
|
|
16
|
+
const paymaster_js_1 = require("./paymaster.js");
|
|
18
17
|
const DEFAULT_RPC = {
|
|
19
18
|
[network_js_1.Network.Testnet]: "https://testnet.fogo.io",
|
|
20
19
|
[network_js_1.Network.Mainnet]: "https://mainnet.fogo.io",
|
|
@@ -101,7 +100,7 @@ const sendToPaymaster = async (connection, domain, sessionKey, instructions, wal
|
|
|
101
100
|
return sponsorAndSendResponseSchema.parse(await response.json());
|
|
102
101
|
}
|
|
103
102
|
else {
|
|
104
|
-
throw new PaymasterResponseError(response.status, await response.text());
|
|
103
|
+
throw new paymaster_js_1.PaymasterResponseError(response.status, await response.text());
|
|
105
104
|
}
|
|
106
105
|
}
|
|
107
106
|
else {
|
|
@@ -119,7 +118,9 @@ const buildTransaction = async (connection, domain, sessionKey, signerKeys, inst
|
|
|
119
118
|
? Promise.resolve(undefined)
|
|
120
119
|
: getAddressLookupTable(connection.connection, connection.addressLookupTableCache, extraConfig.addressLookupTable),
|
|
121
120
|
Promise.all(signerKeys.map((signer) => (0, kit_1.createSignerFromKeyPair)(signer))),
|
|
122
|
-
|
|
121
|
+
extraConfig?.variation === undefined
|
|
122
|
+
? Promise.resolve(new bn_js_1.default(0))
|
|
123
|
+
: (0, paymaster_js_1.getPaymasterFee)(connection.paymaster ?? DEFAULT_PAYMASTER[connection.network], domain, extraConfig.variation, feeMint),
|
|
123
124
|
sessionKey === undefined
|
|
124
125
|
? Promise.resolve(undefined)
|
|
125
126
|
: (0, kit_1.getAddressFromPublicKey)(sessionKey.publicKey),
|
|
@@ -133,7 +134,8 @@ const buildTransaction = async (connection, domain, sessionKey, signerKeys, inst
|
|
|
133
134
|
});
|
|
134
135
|
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
|
|
135
136
|
? (0, compat_1.fromLegacyTransactionInstruction)(instruction)
|
|
136
|
-
: instruction), tx), (tx) => tollboothInstruction === undefined
|
|
137
|
+
: instruction), tx), (tx) => tollboothInstruction === undefined ||
|
|
138
|
+
tx.instructions.some((instruction) => instruction.programAddress == sessions_idls_1.TollboothIdl.address)
|
|
137
139
|
? tx
|
|
138
140
|
: (0, kit_1.appendTransactionMessageInstructions)([tollboothInstruction], tx), (tx) => addressLookupTable === undefined
|
|
139
141
|
? tx
|
|
@@ -141,24 +143,15 @@ const buildTransaction = async (connection, domain, sessionKey, signerKeys, inst
|
|
|
141
143
|
[(0, compat_1.fromLegacyPublicKey)(addressLookupTable.key)]: addressLookupTable.state.addresses.map((address) => (0, compat_1.fromLegacyPublicKey)(address)),
|
|
142
144
|
}), (tx) => (0, kit_1.addSignersToTransactionMessage)(signers, tx)));
|
|
143
145
|
};
|
|
144
|
-
const
|
|
145
|
-
const hash = (0, sha2_1.sha256)(domain);
|
|
146
|
-
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("toll_recipient"), Buffer.from([0]), hash], new web3_js_1.PublicKey(sessions_idls_1.TollboothIdl.address))[0];
|
|
147
|
-
};
|
|
148
|
-
const buildTollboothInstructionIfNeeded = async ({ sessionKeyAddress, walletPublicKey, domain, feeMint, feeAmount, }) => {
|
|
146
|
+
const buildTollboothInstructionIfNeeded = ({ sessionKeyAddress, walletPublicKey, domain, feeMint, feeAmount, }) => {
|
|
149
147
|
if (feeAmount.gt(new bn_js_1.default(0)) && sessionKeyAddress !== undefined) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
destination: (0, spl_token_1.getAssociatedTokenAddressSync)(feeMint, recipient, true),
|
|
158
|
-
mint: feeMint,
|
|
159
|
-
})
|
|
160
|
-
.instruction();
|
|
161
|
-
return (0, compat_1.fromLegacyTransactionInstruction)(instruction);
|
|
148
|
+
return (0, instructions_js_1.createPaymasterFeeInstruction)({
|
|
149
|
+
sessionKey: new web3_js_1.PublicKey(sessionKeyAddress),
|
|
150
|
+
walletPublicKey,
|
|
151
|
+
domain,
|
|
152
|
+
feeMint,
|
|
153
|
+
feeAmount,
|
|
154
|
+
}).then(compat_1.fromLegacyTransactionInstruction);
|
|
162
155
|
}
|
|
163
156
|
else {
|
|
164
157
|
return undefined;
|
|
@@ -208,31 +201,13 @@ const getSponsor = async (options, sponsorCache, domain) => {
|
|
|
208
201
|
return sponsor;
|
|
209
202
|
}
|
|
210
203
|
else {
|
|
211
|
-
throw new PaymasterResponseError(response.status, await response.text());
|
|
204
|
+
throw new paymaster_js_1.PaymasterResponseError(response.status, await response.text());
|
|
212
205
|
}
|
|
213
206
|
}
|
|
214
207
|
else {
|
|
215
208
|
return value;
|
|
216
209
|
}
|
|
217
210
|
};
|
|
218
|
-
const getFee = async (options, domain, variation, mint) => {
|
|
219
|
-
if (variation) {
|
|
220
|
-
const url = new URL("/api/fee", options.paymaster ?? DEFAULT_PAYMASTER[options.network]);
|
|
221
|
-
url.searchParams.set("domain", domain);
|
|
222
|
-
url.searchParams.set("variation", variation);
|
|
223
|
-
url.searchParams.set("mint", mint.toBase58());
|
|
224
|
-
const response = await fetch(url);
|
|
225
|
-
if (response.status === 200) {
|
|
226
|
-
return new bn_js_1.default(await response.text());
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
throw new PaymasterResponseError(response.status, await response.text());
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
return new bn_js_1.default(0);
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
211
|
const getAddressLookupTable = async (connection, addressLookupTableCache, addressLookupTableAddress) => {
|
|
237
212
|
const value = addressLookupTableCache.get(addressLookupTableAddress);
|
|
238
213
|
if (value === undefined) {
|
|
@@ -249,9 +224,3 @@ const getAddressLookupTable = async (connection, addressLookupTableCache, addres
|
|
|
249
224
|
return value;
|
|
250
225
|
}
|
|
251
226
|
};
|
|
252
|
-
class PaymasterResponseError extends Error {
|
|
253
|
-
constructor(statusCode, message) {
|
|
254
|
-
super(`Paymaster sent a ${statusCode.toString()} response: ${message}`);
|
|
255
|
-
this.name = "PaymasterResponseError";
|
|
256
|
-
}
|
|
257
|
-
}
|
package/cjs/index.d.ts
CHANGED
|
@@ -7,8 +7,9 @@ import type { TransactionOrInstructions, TransactionResult } from "./connection.
|
|
|
7
7
|
import type { SendTransactionOptions, SessionContext } from "./context.js";
|
|
8
8
|
export { type Connection, createSessionConnection, type TransactionOrInstructions, type TransactionResult, TransactionResultType, } from "./connection.js";
|
|
9
9
|
export { createSessionContext, type SendTransactionOptions, type SessionContext, } from "./context.js";
|
|
10
|
-
export { createSessionUnwrapInstruction, createSessionWrapInstructions, createSystemProgramSessionWrapInstruction, } from "./instructions.js";
|
|
10
|
+
export { createPaymasterFeeInstruction, createSessionUnwrapInstruction, createSessionWrapInstructions, createSystemProgramSessionWrapInstruction, } from "./instructions.js";
|
|
11
11
|
export { Network } from "./network.js";
|
|
12
|
+
export { getPaymasterFee } from "./paymaster.js";
|
|
12
13
|
type EstablishSessionOptions = {
|
|
13
14
|
context: SessionContext;
|
|
14
15
|
walletPublicKey: PublicKey;
|
|
@@ -61,7 +62,7 @@ export declare const getSessionAccount: (connection: Connection, sessionPublicKe
|
|
|
61
62
|
expiration: Date;
|
|
62
63
|
extra: unknown;
|
|
63
64
|
major: number;
|
|
64
|
-
minor: 1 | 2 | 3
|
|
65
|
+
minor: 4 | 1 | 2 | 3;
|
|
65
66
|
user: PublicKey;
|
|
66
67
|
sponsor: PublicKey;
|
|
67
68
|
} | undefined>;
|
|
@@ -2042,7 +2043,7 @@ declare const sessionInfoSchema: z.ZodEffects<z.ZodObject<{
|
|
|
2042
2043
|
expiration: Date;
|
|
2043
2044
|
extra: unknown;
|
|
2044
2045
|
major: number;
|
|
2045
|
-
minor: 1 | 2 | 3
|
|
2046
|
+
minor: 4 | 1 | 2 | 3;
|
|
2046
2047
|
user: PublicKey;
|
|
2047
2048
|
sponsor: PublicKey;
|
|
2048
2049
|
} | undefined, {
|
|
@@ -2339,7 +2340,7 @@ export declare const verifyLogInToken: (token: string, connection: Connection) =
|
|
|
2339
2340
|
expiration: Date;
|
|
2340
2341
|
extra: unknown;
|
|
2341
2342
|
major: number;
|
|
2342
|
-
minor: 1 | 2 | 3
|
|
2343
|
+
minor: 4 | 1 | 2 | 3;
|
|
2343
2344
|
user: PublicKey;
|
|
2344
2345
|
sponsor: PublicKey;
|
|
2345
2346
|
} | undefined>;
|
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.sendNativeTransfer = 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.Network = exports.createSystemProgramSessionWrapInstruction = exports.createSessionWrapInstructions = exports.createSessionUnwrapInstruction = exports.createSessionContext = exports.TransactionResultType = exports.createSessionConnection = void 0;
|
|
6
|
+
exports.verifyLogInToken = exports.createLogInToken = exports.bridgeIn = exports.bridgeOut = exports.sendNativeTransfer = 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.getPaymasterFee = exports.Network = exports.createSystemProgramSessionWrapInstruction = exports.createSessionWrapInstructions = exports.createSessionUnwrapInstruction = exports.createPaymasterFeeInstruction = exports.createSessionContext = exports.TransactionResultType = exports.createSessionConnection = 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");
|
|
@@ -35,11 +35,14 @@ Object.defineProperty(exports, "TransactionResultType", { enumerable: true, get:
|
|
|
35
35
|
var context_js_2 = require("./context.js");
|
|
36
36
|
Object.defineProperty(exports, "createSessionContext", { enumerable: true, get: function () { return context_js_2.createSessionContext; } });
|
|
37
37
|
var instructions_js_2 = require("./instructions.js");
|
|
38
|
+
Object.defineProperty(exports, "createPaymasterFeeInstruction", { enumerable: true, get: function () { return instructions_js_2.createPaymasterFeeInstruction; } });
|
|
38
39
|
Object.defineProperty(exports, "createSessionUnwrapInstruction", { enumerable: true, get: function () { return instructions_js_2.createSessionUnwrapInstruction; } });
|
|
39
40
|
Object.defineProperty(exports, "createSessionWrapInstructions", { enumerable: true, get: function () { return instructions_js_2.createSessionWrapInstructions; } });
|
|
40
41
|
Object.defineProperty(exports, "createSystemProgramSessionWrapInstruction", { enumerable: true, get: function () { return instructions_js_2.createSystemProgramSessionWrapInstruction; } });
|
|
41
42
|
var network_js_2 = require("./network.js");
|
|
42
43
|
Object.defineProperty(exports, "Network", { enumerable: true, get: function () { return network_js_2.Network; } });
|
|
44
|
+
var paymaster_js_1 = require("./paymaster.js");
|
|
45
|
+
Object.defineProperty(exports, "getPaymasterFee", { enumerable: true, get: function () { return paymaster_js_1.getPaymasterFee; } });
|
|
43
46
|
const MESSAGE_HEADER = `Fogo Sessions:
|
|
44
47
|
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.
|
|
45
48
|
`;
|
|
@@ -128,10 +131,36 @@ const getSessionAccount = async (connection, sessionPublicKey) => {
|
|
|
128
131
|
: sessionInfoSchema.parse(new anchor_1.BorshAccountsCoder(sessions_idls_1.SessionManagerIdl).decode("Session", result.data));
|
|
129
132
|
};
|
|
130
133
|
exports.getSessionAccount = getSessionAccount;
|
|
134
|
+
const getDomainRegistryAuthorizedPrograms = async (connection, domain) => {
|
|
135
|
+
const result = await connection.getAccountInfo((0, exports.getDomainRecordAddress)(domain), "confirmed");
|
|
136
|
+
if (result === null) {
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const programs = [];
|
|
141
|
+
for (let i = 0; i < result.data.length; i += 64) {
|
|
142
|
+
programs.push({
|
|
143
|
+
programId: new web3_js_1.PublicKey(result.data.subarray(i, i + 32)),
|
|
144
|
+
signerPda: new web3_js_1.PublicKey(result.data.subarray(i + 32, i + 64)),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return programs;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const authorizedProgramsMatchDomainRegistry = (sessionAuthorizedPrograms, domainAuthorizedPrograms) => {
|
|
151
|
+
if (sessionAuthorizedPrograms.type === AuthorizedProgramsType.All) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
return domainAuthorizedPrograms.every(({ programId: programIdFromRegistry }) => sessionAuthorizedPrograms.programs.some(({ programId }) => programId.equals(programIdFromRegistry)));
|
|
155
|
+
};
|
|
131
156
|
const createSession = async (context, walletPublicKey, sessionKey) => {
|
|
132
157
|
const sessionPublicKey = new web3_js_1.PublicKey(await (0, kit_1.getAddressFromPublicKey)(sessionKey.publicKey));
|
|
133
|
-
const sessionInfo = await
|
|
134
|
-
|
|
158
|
+
const [sessionInfo, domainRegistryAuthorizedPrograms] = await Promise.all([
|
|
159
|
+
(0, exports.getSessionAccount)(context.connection, sessionPublicKey),
|
|
160
|
+
getDomainRegistryAuthorizedPrograms(context.connection, context.domain),
|
|
161
|
+
]);
|
|
162
|
+
return sessionInfo === undefined ||
|
|
163
|
+
!authorizedProgramsMatchDomainRegistry(sessionInfo.authorizedPrograms, domainRegistryAuthorizedPrograms)
|
|
135
164
|
? undefined
|
|
136
165
|
: {
|
|
137
166
|
sessionPublicKey,
|
package/cjs/instructions.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
|
|
2
|
+
import type BN from "bn.js";
|
|
3
3
|
/**
|
|
4
4
|
* Creates the system program instruction `SessionWrap`, only available on Fogo, which allows a session key to transfer native token from its user's wallet to its user's wrapped token associated token account.
|
|
5
5
|
* This instruction may be combined with the `CreateAssociatedTokenAccountIdempotent` and `SyncNative` instructions for a session to wrap tokens on behalf of its user.
|
|
@@ -17,3 +17,15 @@ export declare function createSessionWrapInstructions(sessionKey: PublicKey, wal
|
|
|
17
17
|
* Creates the instruction required to unwrap native tokens within a session.
|
|
18
18
|
*/
|
|
19
19
|
export declare function createSessionUnwrapInstruction(sessionKey: PublicKey, walletPublicKey: PublicKey): TransactionInstruction;
|
|
20
|
+
/**
|
|
21
|
+
* Creates the instruction required to pay the paymaster fee for a transaction.
|
|
22
|
+
* This instruction is only required if the transaction variation has a fee and may be placed anywhere in the instruction list.
|
|
23
|
+
* The fee amount for a variation in a given token can be retrieved using the `getPaymasterFee` function.
|
|
24
|
+
*/
|
|
25
|
+
export declare const createPaymasterFeeInstruction: ({ sessionKey, walletPublicKey, domain, feeMint, feeAmount, }: {
|
|
26
|
+
sessionKey: PublicKey;
|
|
27
|
+
walletPublicKey: PublicKey;
|
|
28
|
+
domain: string;
|
|
29
|
+
feeMint: PublicKey;
|
|
30
|
+
feeAmount: BN;
|
|
31
|
+
}) => Promise<TransactionInstruction>;
|
package/cjs/instructions.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createPaymasterFeeInstruction = void 0;
|
|
3
4
|
exports.createSystemProgramSessionWrapInstruction = createSystemProgramSessionWrapInstruction;
|
|
4
5
|
exports.createSessionWrapInstructions = createSessionWrapInstructions;
|
|
5
6
|
exports.createSessionUnwrapInstruction = createSessionUnwrapInstruction;
|
|
7
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
8
|
+
const sessions_idls_1 = require("@fogo/sessions-idls");
|
|
9
|
+
const sha2_1 = require("@noble/hashes/sha2");
|
|
6
10
|
const spl_token_1 = require("@solana/spl-token");
|
|
7
11
|
const web3_js_1 = require("@solana/web3.js");
|
|
8
12
|
const SESSION_WRAP_DISCRIMINATOR = 4_000_000;
|
|
@@ -54,3 +58,25 @@ function createSessionWrapInstructions(sessionKey, walletPublicKey, amount) {
|
|
|
54
58
|
function createSessionUnwrapInstruction(sessionKey, walletPublicKey) {
|
|
55
59
|
return (0, spl_token_1.createCloseAccountInstruction)(getNativeMintAssociatedTokenAddressSync(walletPublicKey), walletPublicKey, sessionKey);
|
|
56
60
|
}
|
|
61
|
+
const getDomainTollRecipientAddress = (domain) => {
|
|
62
|
+
const hash = (0, sha2_1.sha256)(domain);
|
|
63
|
+
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("toll_recipient"), Buffer.from([0]), hash], new web3_js_1.PublicKey(sessions_idls_1.TollboothIdl.address))[0];
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Creates the instruction required to pay the paymaster fee for a transaction.
|
|
67
|
+
* This instruction is only required if the transaction variation has a fee and may be placed anywhere in the instruction list.
|
|
68
|
+
* The fee amount for a variation in a given token can be retrieved using the `getPaymasterFee` function.
|
|
69
|
+
*/
|
|
70
|
+
const createPaymasterFeeInstruction = ({ sessionKey, walletPublicKey, domain, feeMint, feeAmount, }) => {
|
|
71
|
+
const recipient = getDomainTollRecipientAddress(domain);
|
|
72
|
+
return new sessions_idls_1.TollboothProgram(new anchor_1.AnchorProvider({}, {})).methods
|
|
73
|
+
.payToll(feeAmount, 0)
|
|
74
|
+
.accounts({
|
|
75
|
+
session: sessionKey,
|
|
76
|
+
source: (0, spl_token_1.getAssociatedTokenAddressSync)(feeMint, walletPublicKey),
|
|
77
|
+
destination: (0, spl_token_1.getAssociatedTokenAddressSync)(feeMint, recipient, true),
|
|
78
|
+
mint: feeMint,
|
|
79
|
+
})
|
|
80
|
+
.instruction();
|
|
81
|
+
};
|
|
82
|
+
exports.createPaymasterFeeInstruction = createPaymasterFeeInstruction;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import BN from "bn.js";
|
|
3
|
+
export declare class PaymasterResponseError extends Error {
|
|
4
|
+
constructor(statusCode: number, message: string);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Retrieves the paymaster fee amount from the paymaster server for a given transaction variation when paid in a given mint.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getPaymasterFee: (paymaster: string | URL, domain: string, variation: string, mint: PublicKey) => Promise<BN>;
|
package/cjs/paymaster.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getPaymasterFee = exports.PaymasterResponseError = void 0;
|
|
7
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
8
|
+
class PaymasterResponseError extends Error {
|
|
9
|
+
constructor(statusCode, message) {
|
|
10
|
+
super(`Paymaster sent a ${statusCode.toString()} response: ${message}`);
|
|
11
|
+
this.name = "PaymasterResponseError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.PaymasterResponseError = PaymasterResponseError;
|
|
15
|
+
/**
|
|
16
|
+
* Retrieves the paymaster fee amount from the paymaster server for a given transaction variation when paid in a given mint.
|
|
17
|
+
*/
|
|
18
|
+
const getPaymasterFee = async (paymaster, domain, variation, mint) => {
|
|
19
|
+
const url = new URL("/api/fee", paymaster);
|
|
20
|
+
url.searchParams.set("domain", domain);
|
|
21
|
+
url.searchParams.set("variation", variation);
|
|
22
|
+
url.searchParams.set("mint", mint.toBase58());
|
|
23
|
+
const response = await fetch(url);
|
|
24
|
+
if (response.status === 200) {
|
|
25
|
+
return new bn_js_1.default(await response.text());
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
throw new PaymasterResponseError(response.status, await response.text());
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
exports.getPaymasterFee = getPaymasterFee;
|
package/esm/connection.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { TollboothIdl, TollboothProgram } from "@fogo/sessions-idls";
|
|
3
|
-
import { sha256 } from "@noble/hashes/sha2";
|
|
1
|
+
import { TollboothIdl } from "@fogo/sessions-idls";
|
|
4
2
|
import { fromLegacyKeypair, fromLegacyPublicKey, fromLegacyTransactionInstruction, fromVersionedTransaction, } from "@solana/compat";
|
|
5
3
|
import { addSignersToTransactionMessage, appendTransactionMessageInstructions, compressTransactionMessageUsingAddressLookupTables, createSignerFromKeyPair, createSolanaRpc, createTransactionMessage, getAddressFromPublicKey, getBase64EncodedWireTransaction, partiallySignTransaction, partiallySignTransactionMessageWithSigners, pipe, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, } from "@solana/kit";
|
|
6
|
-
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
|
|
7
4
|
import { Keypair, PublicKey, TransactionInstruction, VersionedTransaction, Connection as Web3Connection, } from "@solana/web3.js";
|
|
8
5
|
import BN from "bn.js";
|
|
9
6
|
import { z } from "zod";
|
|
7
|
+
import { createPaymasterFeeInstruction } from "./instructions.js";
|
|
10
8
|
import { USDC_MINT } from "./mints.js";
|
|
11
9
|
import { Network } from "./network.js";
|
|
10
|
+
import { getPaymasterFee, PaymasterResponseError } from "./paymaster.js";
|
|
12
11
|
const DEFAULT_RPC = {
|
|
13
12
|
[Network.Testnet]: "https://testnet.fogo.io",
|
|
14
13
|
[Network.Mainnet]: "https://mainnet.fogo.io",
|
|
@@ -112,7 +111,9 @@ const buildTransaction = async (connection, domain, sessionKey, signerKeys, inst
|
|
|
112
111
|
? Promise.resolve(undefined)
|
|
113
112
|
: getAddressLookupTable(connection.connection, connection.addressLookupTableCache, extraConfig.addressLookupTable),
|
|
114
113
|
Promise.all(signerKeys.map((signer) => createSignerFromKeyPair(signer))),
|
|
115
|
-
|
|
114
|
+
extraConfig?.variation === undefined
|
|
115
|
+
? Promise.resolve(new BN(0))
|
|
116
|
+
: getPaymasterFee(connection.paymaster ?? DEFAULT_PAYMASTER[connection.network], domain, extraConfig.variation, feeMint),
|
|
116
117
|
sessionKey === undefined
|
|
117
118
|
? Promise.resolve(undefined)
|
|
118
119
|
: getAddressFromPublicKey(sessionKey.publicKey),
|
|
@@ -126,7 +127,8 @@ const buildTransaction = async (connection, domain, sessionKey, signerKeys, inst
|
|
|
126
127
|
});
|
|
127
128
|
return partiallySignTransactionMessageWithSigners(pipe(createTransactionMessage({ version: 0 }), (tx) => setTransactionMessageFeePayer(fromLegacyPublicKey(sponsor), tx), (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) => appendTransactionMessageInstructions(instructions.map((instruction) => instruction instanceof TransactionInstruction
|
|
128
129
|
? fromLegacyTransactionInstruction(instruction)
|
|
129
|
-
: instruction), tx), (tx) => tollboothInstruction === undefined
|
|
130
|
+
: instruction), tx), (tx) => tollboothInstruction === undefined ||
|
|
131
|
+
tx.instructions.some((instruction) => instruction.programAddress == TollboothIdl.address)
|
|
130
132
|
? tx
|
|
131
133
|
: appendTransactionMessageInstructions([tollboothInstruction], tx), (tx) => addressLookupTable === undefined
|
|
132
134
|
? tx
|
|
@@ -134,24 +136,15 @@ const buildTransaction = async (connection, domain, sessionKey, signerKeys, inst
|
|
|
134
136
|
[fromLegacyPublicKey(addressLookupTable.key)]: addressLookupTable.state.addresses.map((address) => fromLegacyPublicKey(address)),
|
|
135
137
|
}), (tx) => addSignersToTransactionMessage(signers, tx)));
|
|
136
138
|
};
|
|
137
|
-
const
|
|
138
|
-
const hash = sha256(domain);
|
|
139
|
-
return PublicKey.findProgramAddressSync([Buffer.from("toll_recipient"), Buffer.from([0]), hash], new PublicKey(TollboothIdl.address))[0];
|
|
140
|
-
};
|
|
141
|
-
const buildTollboothInstructionIfNeeded = async ({ sessionKeyAddress, walletPublicKey, domain, feeMint, feeAmount, }) => {
|
|
139
|
+
const buildTollboothInstructionIfNeeded = ({ sessionKeyAddress, walletPublicKey, domain, feeMint, feeAmount, }) => {
|
|
142
140
|
if (feeAmount.gt(new BN(0)) && sessionKeyAddress !== undefined) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
destination: getAssociatedTokenAddressSync(feeMint, recipient, true),
|
|
151
|
-
mint: feeMint,
|
|
152
|
-
})
|
|
153
|
-
.instruction();
|
|
154
|
-
return fromLegacyTransactionInstruction(instruction);
|
|
141
|
+
return createPaymasterFeeInstruction({
|
|
142
|
+
sessionKey: new PublicKey(sessionKeyAddress),
|
|
143
|
+
walletPublicKey,
|
|
144
|
+
domain,
|
|
145
|
+
feeMint,
|
|
146
|
+
feeAmount,
|
|
147
|
+
}).then(fromLegacyTransactionInstruction);
|
|
155
148
|
}
|
|
156
149
|
else {
|
|
157
150
|
return undefined;
|
|
@@ -208,24 +201,6 @@ const getSponsor = async (options, sponsorCache, domain) => {
|
|
|
208
201
|
return value;
|
|
209
202
|
}
|
|
210
203
|
};
|
|
211
|
-
const getFee = async (options, domain, variation, mint) => {
|
|
212
|
-
if (variation) {
|
|
213
|
-
const url = new URL("/api/fee", options.paymaster ?? DEFAULT_PAYMASTER[options.network]);
|
|
214
|
-
url.searchParams.set("domain", domain);
|
|
215
|
-
url.searchParams.set("variation", variation);
|
|
216
|
-
url.searchParams.set("mint", mint.toBase58());
|
|
217
|
-
const response = await fetch(url);
|
|
218
|
-
if (response.status === 200) {
|
|
219
|
-
return new BN(await response.text());
|
|
220
|
-
}
|
|
221
|
-
else {
|
|
222
|
-
throw new PaymasterResponseError(response.status, await response.text());
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
return new BN(0);
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
204
|
const getAddressLookupTable = async (connection, addressLookupTableCache, addressLookupTableAddress) => {
|
|
230
205
|
const value = addressLookupTableCache.get(addressLookupTableAddress);
|
|
231
206
|
if (value === undefined) {
|
|
@@ -242,9 +217,3 @@ const getAddressLookupTable = async (connection, addressLookupTableCache, addres
|
|
|
242
217
|
return value;
|
|
243
218
|
}
|
|
244
219
|
};
|
|
245
|
-
class PaymasterResponseError extends Error {
|
|
246
|
-
constructor(statusCode, message) {
|
|
247
|
-
super(`Paymaster sent a ${statusCode.toString()} response: ${message}`);
|
|
248
|
-
this.name = "PaymasterResponseError";
|
|
249
|
-
}
|
|
250
|
-
}
|
package/esm/index.d.ts
CHANGED
|
@@ -7,8 +7,9 @@ import type { TransactionOrInstructions, TransactionResult } from "./connection.
|
|
|
7
7
|
import type { SendTransactionOptions, SessionContext } from "./context.js";
|
|
8
8
|
export { type Connection, createSessionConnection, type TransactionOrInstructions, type TransactionResult, TransactionResultType, } from "./connection.js";
|
|
9
9
|
export { createSessionContext, type SendTransactionOptions, type SessionContext, } from "./context.js";
|
|
10
|
-
export { createSessionUnwrapInstruction, createSessionWrapInstructions, createSystemProgramSessionWrapInstruction, } from "./instructions.js";
|
|
10
|
+
export { createPaymasterFeeInstruction, createSessionUnwrapInstruction, createSessionWrapInstructions, createSystemProgramSessionWrapInstruction, } from "./instructions.js";
|
|
11
11
|
export { Network } from "./network.js";
|
|
12
|
+
export { getPaymasterFee } from "./paymaster.js";
|
|
12
13
|
type EstablishSessionOptions = {
|
|
13
14
|
context: SessionContext;
|
|
14
15
|
walletPublicKey: PublicKey;
|
|
@@ -61,7 +62,7 @@ export declare const getSessionAccount: (connection: Connection, sessionPublicKe
|
|
|
61
62
|
expiration: Date;
|
|
62
63
|
extra: unknown;
|
|
63
64
|
major: number;
|
|
64
|
-
minor: 1 | 2 | 3
|
|
65
|
+
minor: 4 | 1 | 2 | 3;
|
|
65
66
|
user: PublicKey;
|
|
66
67
|
sponsor: PublicKey;
|
|
67
68
|
} | undefined>;
|
|
@@ -2042,7 +2043,7 @@ declare const sessionInfoSchema: z.ZodEffects<z.ZodObject<{
|
|
|
2042
2043
|
expiration: Date;
|
|
2043
2044
|
extra: unknown;
|
|
2044
2045
|
major: number;
|
|
2045
|
-
minor: 1 | 2 | 3
|
|
2046
|
+
minor: 4 | 1 | 2 | 3;
|
|
2046
2047
|
user: PublicKey;
|
|
2047
2048
|
sponsor: PublicKey;
|
|
2048
2049
|
} | undefined, {
|
|
@@ -2339,7 +2340,7 @@ export declare const verifyLogInToken: (token: string, connection: Connection) =
|
|
|
2339
2340
|
expiration: Date;
|
|
2340
2341
|
extra: unknown;
|
|
2341
2342
|
major: number;
|
|
2342
|
-
minor: 1 | 2 | 3
|
|
2343
|
+
minor: 4 | 1 | 2 | 3;
|
|
2343
2344
|
user: PublicKey;
|
|
2344
2345
|
sponsor: PublicKey;
|
|
2345
2346
|
} | undefined>;
|
package/esm/index.js
CHANGED
|
@@ -25,8 +25,9 @@ import { USDC_DECIMALS, USDC_MINT } from "./mints.js";
|
|
|
25
25
|
import { Network } from "./network.js";
|
|
26
26
|
export { createSessionConnection, TransactionResultType, } from "./connection.js";
|
|
27
27
|
export { createSessionContext, } from "./context.js";
|
|
28
|
-
export { createSessionUnwrapInstruction, createSessionWrapInstructions, createSystemProgramSessionWrapInstruction, } from "./instructions.js";
|
|
28
|
+
export { createPaymasterFeeInstruction, createSessionUnwrapInstruction, createSessionWrapInstructions, createSystemProgramSessionWrapInstruction, } from "./instructions.js";
|
|
29
29
|
export { Network } from "./network.js";
|
|
30
|
+
export { getPaymasterFee } from "./paymaster.js";
|
|
30
31
|
const MESSAGE_HEADER = `Fogo Sessions:
|
|
31
32
|
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.
|
|
32
33
|
`;
|
|
@@ -110,10 +111,36 @@ export const getSessionAccount = async (connection, sessionPublicKey) => {
|
|
|
110
111
|
? undefined
|
|
111
112
|
: sessionInfoSchema.parse(new BorshAccountsCoder(SessionManagerIdl).decode("Session", result.data));
|
|
112
113
|
};
|
|
114
|
+
const getDomainRegistryAuthorizedPrograms = async (connection, domain) => {
|
|
115
|
+
const result = await connection.getAccountInfo(getDomainRecordAddress(domain), "confirmed");
|
|
116
|
+
if (result === null) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const programs = [];
|
|
121
|
+
for (let i = 0; i < result.data.length; i += 64) {
|
|
122
|
+
programs.push({
|
|
123
|
+
programId: new PublicKey(result.data.subarray(i, i + 32)),
|
|
124
|
+
signerPda: new PublicKey(result.data.subarray(i + 32, i + 64)),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return programs;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const authorizedProgramsMatchDomainRegistry = (sessionAuthorizedPrograms, domainAuthorizedPrograms) => {
|
|
131
|
+
if (sessionAuthorizedPrograms.type === AuthorizedProgramsType.All) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return domainAuthorizedPrograms.every(({ programId: programIdFromRegistry }) => sessionAuthorizedPrograms.programs.some(({ programId }) => programId.equals(programIdFromRegistry)));
|
|
135
|
+
};
|
|
113
136
|
const createSession = async (context, walletPublicKey, sessionKey) => {
|
|
114
137
|
const sessionPublicKey = new PublicKey(await getAddressFromPublicKey(sessionKey.publicKey));
|
|
115
|
-
const sessionInfo = await
|
|
116
|
-
|
|
138
|
+
const [sessionInfo, domainRegistryAuthorizedPrograms] = await Promise.all([
|
|
139
|
+
getSessionAccount(context.connection, sessionPublicKey),
|
|
140
|
+
getDomainRegistryAuthorizedPrograms(context.connection, context.domain),
|
|
141
|
+
]);
|
|
142
|
+
return sessionInfo === undefined ||
|
|
143
|
+
!authorizedProgramsMatchDomainRegistry(sessionInfo.authorizedPrograms, domainRegistryAuthorizedPrograms)
|
|
117
144
|
? undefined
|
|
118
145
|
: {
|
|
119
146
|
sessionPublicKey,
|
package/esm/instructions.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
|
|
2
|
+
import type BN from "bn.js";
|
|
3
3
|
/**
|
|
4
4
|
* Creates the system program instruction `SessionWrap`, only available on Fogo, which allows a session key to transfer native token from its user's wallet to its user's wrapped token associated token account.
|
|
5
5
|
* This instruction may be combined with the `CreateAssociatedTokenAccountIdempotent` and `SyncNative` instructions for a session to wrap tokens on behalf of its user.
|
|
@@ -17,3 +17,15 @@ export declare function createSessionWrapInstructions(sessionKey: PublicKey, wal
|
|
|
17
17
|
* Creates the instruction required to unwrap native tokens within a session.
|
|
18
18
|
*/
|
|
19
19
|
export declare function createSessionUnwrapInstruction(sessionKey: PublicKey, walletPublicKey: PublicKey): TransactionInstruction;
|
|
20
|
+
/**
|
|
21
|
+
* Creates the instruction required to pay the paymaster fee for a transaction.
|
|
22
|
+
* This instruction is only required if the transaction variation has a fee and may be placed anywhere in the instruction list.
|
|
23
|
+
* The fee amount for a variation in a given token can be retrieved using the `getPaymasterFee` function.
|
|
24
|
+
*/
|
|
25
|
+
export declare const createPaymasterFeeInstruction: ({ sessionKey, walletPublicKey, domain, feeMint, feeAmount, }: {
|
|
26
|
+
sessionKey: PublicKey;
|
|
27
|
+
walletPublicKey: PublicKey;
|
|
28
|
+
domain: string;
|
|
29
|
+
feeMint: PublicKey;
|
|
30
|
+
feeAmount: BN;
|
|
31
|
+
}) => Promise<TransactionInstruction>;
|
package/esm/instructions.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { AnchorProvider } from "@coral-xyz/anchor";
|
|
2
|
+
import { TollboothIdl, TollboothProgram } from "@fogo/sessions-idls";
|
|
3
|
+
import { sha256 } from "@noble/hashes/sha2";
|
|
1
4
|
import { createAssociatedTokenAccountIdempotentInstruction, createCloseAccountInstruction, createSyncNativeInstruction, getAssociatedTokenAddressSync, NATIVE_MINT, } from "@solana/spl-token";
|
|
2
|
-
import { SystemProgram, TransactionInstruction } from "@solana/web3.js";
|
|
5
|
+
import { PublicKey, SystemProgram, TransactionInstruction, } from "@solana/web3.js";
|
|
3
6
|
const SESSION_WRAP_DISCRIMINATOR = 4_000_000;
|
|
4
7
|
function getNativeMintAssociatedTokenAddressSync(walletPublicKey) {
|
|
5
8
|
return getAssociatedTokenAddressSync(NATIVE_MINT, walletPublicKey);
|
|
@@ -49,3 +52,24 @@ export function createSessionWrapInstructions(sessionKey, walletPublicKey, amoun
|
|
|
49
52
|
export function createSessionUnwrapInstruction(sessionKey, walletPublicKey) {
|
|
50
53
|
return createCloseAccountInstruction(getNativeMintAssociatedTokenAddressSync(walletPublicKey), walletPublicKey, sessionKey);
|
|
51
54
|
}
|
|
55
|
+
const getDomainTollRecipientAddress = (domain) => {
|
|
56
|
+
const hash = sha256(domain);
|
|
57
|
+
return PublicKey.findProgramAddressSync([Buffer.from("toll_recipient"), Buffer.from([0]), hash], new PublicKey(TollboothIdl.address))[0];
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Creates the instruction required to pay the paymaster fee for a transaction.
|
|
61
|
+
* This instruction is only required if the transaction variation has a fee and may be placed anywhere in the instruction list.
|
|
62
|
+
* The fee amount for a variation in a given token can be retrieved using the `getPaymasterFee` function.
|
|
63
|
+
*/
|
|
64
|
+
export const createPaymasterFeeInstruction = ({ sessionKey, walletPublicKey, domain, feeMint, feeAmount, }) => {
|
|
65
|
+
const recipient = getDomainTollRecipientAddress(domain);
|
|
66
|
+
return new TollboothProgram(new AnchorProvider({}, {})).methods
|
|
67
|
+
.payToll(feeAmount, 0)
|
|
68
|
+
.accounts({
|
|
69
|
+
session: sessionKey,
|
|
70
|
+
source: getAssociatedTokenAddressSync(feeMint, walletPublicKey),
|
|
71
|
+
destination: getAssociatedTokenAddressSync(feeMint, recipient, true),
|
|
72
|
+
mint: feeMint,
|
|
73
|
+
})
|
|
74
|
+
.instruction();
|
|
75
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import BN from "bn.js";
|
|
3
|
+
export declare class PaymasterResponseError extends Error {
|
|
4
|
+
constructor(statusCode: number, message: string);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Retrieves the paymaster fee amount from the paymaster server for a given transaction variation when paid in a given mint.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getPaymasterFee: (paymaster: string | URL, domain: string, variation: string, mint: PublicKey) => Promise<BN>;
|
package/esm/paymaster.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import BN from "bn.js";
|
|
2
|
+
export class PaymasterResponseError extends Error {
|
|
3
|
+
constructor(statusCode, message) {
|
|
4
|
+
super(`Paymaster sent a ${statusCode.toString()} response: ${message}`);
|
|
5
|
+
this.name = "PaymasterResponseError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Retrieves the paymaster fee amount from the paymaster server for a given transaction variation when paid in a given mint.
|
|
10
|
+
*/
|
|
11
|
+
export const getPaymasterFee = async (paymaster, domain, variation, mint) => {
|
|
12
|
+
const url = new URL("/api/fee", paymaster);
|
|
13
|
+
url.searchParams.set("domain", domain);
|
|
14
|
+
url.searchParams.set("variation", variation);
|
|
15
|
+
url.searchParams.set("mint", mint.toBase58());
|
|
16
|
+
const response = await fetch(url);
|
|
17
|
+
if (response.status === 200) {
|
|
18
|
+
return new BN(await response.text());
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
throw new PaymasterResponseError(response.status, await response.text());
|
|
22
|
+
}
|
|
23
|
+
};
|