@fogo/sessions-sdk 0.0.17 → 0.0.18
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.d.ts +57 -0
- package/cjs/connection.js +165 -0
- package/cjs/context.d.ts +11 -36
- package/cjs/context.js +8 -126
- package/cjs/index.d.ts +4 -2
- package/cjs/index.js +10 -7
- package/esm/connection.d.ts +57 -0
- package/esm/connection.js +161 -0
- package/esm/context.d.ts +11 -36
- package/esm/context.js +8 -126
- package/esm/index.d.ts +4 -2
- package/esm/index.js +3 -2
- package/package.json +1 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Transaction, Instruction, TransactionWithLifetime } from "@solana/kit";
|
|
2
|
+
import type { AddressLookupTableAccount, TransactionError } from "@solana/web3.js";
|
|
3
|
+
import { Connection as Web3Connection, TransactionInstruction, VersionedTransaction, PublicKey } from "@solana/web3.js";
|
|
4
|
+
export declare enum Network {
|
|
5
|
+
Testnet = 0,
|
|
6
|
+
Mainnet = 1
|
|
7
|
+
}
|
|
8
|
+
export declare const DEFAULT_RPC: {
|
|
9
|
+
0: string;
|
|
10
|
+
1: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const DEFAULT_PAYMASTER: {
|
|
13
|
+
0: string;
|
|
14
|
+
1: string;
|
|
15
|
+
};
|
|
16
|
+
export declare enum TransactionResultType {
|
|
17
|
+
Success = 0,
|
|
18
|
+
Failed = 1
|
|
19
|
+
}
|
|
20
|
+
declare const TransactionResult: {
|
|
21
|
+
Success: (signature: string) => {
|
|
22
|
+
type: TransactionResultType.Success;
|
|
23
|
+
signature: string;
|
|
24
|
+
};
|
|
25
|
+
Failed: (signature: string, error: TransactionError) => {
|
|
26
|
+
type: TransactionResultType.Failed;
|
|
27
|
+
signature: string;
|
|
28
|
+
error: TransactionError;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
export type TransactionResult = ReturnType<(typeof TransactionResult)[keyof typeof TransactionResult]>;
|
|
32
|
+
export declare const createSessionConnection: (options: {
|
|
33
|
+
network: Network;
|
|
34
|
+
rpc?: string | URL | undefined;
|
|
35
|
+
paymaster?: undefined;
|
|
36
|
+
sendToPaymaster?: undefined;
|
|
37
|
+
sponsor?: undefined;
|
|
38
|
+
} | ({
|
|
39
|
+
network?: Network | undefined;
|
|
40
|
+
rpc: string | URL;
|
|
41
|
+
} & ({
|
|
42
|
+
paymaster: string | URL;
|
|
43
|
+
sendToPaymaster?: undefined;
|
|
44
|
+
sponsor?: undefined;
|
|
45
|
+
} | {
|
|
46
|
+
paymaster?: undefined;
|
|
47
|
+
sendToPaymaster: (transaction: Transaction) => Promise<TransactionResult>;
|
|
48
|
+
sponsor: PublicKey;
|
|
49
|
+
}))) => {
|
|
50
|
+
rpc: import("@solana/kit").Rpc<import("@solana/kit").RequestAirdropApi & import("@solana/kit").GetAccountInfoApi & import("@solana/kit").GetBalanceApi & import("@solana/kit").GetBlockApi & import("@solana/kit").GetBlockCommitmentApi & import("@solana/kit").GetBlockHeightApi & import("@solana/kit").GetBlockProductionApi & import("@solana/kit").GetBlocksApi & import("@solana/kit").GetBlocksWithLimitApi & import("@solana/kit").GetBlockTimeApi & import("@solana/kit").GetClusterNodesApi & import("@solana/kit").GetEpochInfoApi & import("@solana/kit").GetEpochScheduleApi & import("@solana/kit").GetFeeForMessageApi & import("@solana/kit").GetFirstAvailableBlockApi & import("@solana/kit").GetGenesisHashApi & import("@solana/kit").GetHealthApi & import("@solana/kit").GetHighestSnapshotSlotApi & import("@solana/kit").GetIdentityApi & import("@solana/kit").GetInflationGovernorApi & import("@solana/kit").GetInflationRateApi & import("@solana/kit").GetInflationRewardApi & import("@solana/kit").GetLargestAccountsApi & import("@solana/kit").GetLatestBlockhashApi & import("@solana/kit").GetLeaderScheduleApi & import("@solana/kit").GetMaxRetransmitSlotApi & import("@solana/kit").GetMaxShredInsertSlotApi & import("@solana/kit").GetMinimumBalanceForRentExemptionApi & import("@solana/kit").GetMultipleAccountsApi & import("@solana/kit").GetProgramAccountsApi & import("@solana/kit").GetRecentPerformanceSamplesApi & import("@solana/kit").GetRecentPrioritizationFeesApi & import("@solana/kit").GetSignaturesForAddressApi & import("@solana/kit").GetSignatureStatusesApi & import("@solana/kit").GetSlotApi & import("@solana/kit").GetSlotLeaderApi & import("@solana/kit").GetSlotLeadersApi & import("@solana/kit").GetStakeMinimumDelegationApi & import("@solana/kit").GetSupplyApi & import("@solana/kit").GetTokenAccountBalanceApi & import("@solana/kit").GetTokenAccountsByDelegateApi & import("@solana/kit").GetTokenAccountsByOwnerApi & import("@solana/kit").GetTokenLargestAccountsApi & import("@solana/kit").GetTokenSupplyApi & import("@solana/kit").GetTransactionApi & import("@solana/kit").GetTransactionCountApi & import("@solana/kit").GetVersionApi & import("@solana/kit").GetVoteAccountsApi & import("@solana/kit").IsBlockhashValidApi & import("@solana/kit").MinimumLedgerSlotApi & import("@solana/kit").SendTransactionApi & import("@solana/kit").SimulateTransactionApi>;
|
|
51
|
+
connection: Web3Connection;
|
|
52
|
+
sendToPaymaster: (domain: string, sponsor: PublicKey, addressLookupTables: AddressLookupTableAccount[] | undefined, sessionKey: CryptoKeyPair | undefined, instructions: (TransactionInstruction | Instruction)[] | VersionedTransaction | (Transaction & TransactionWithLifetime)) => Promise<TransactionResult>;
|
|
53
|
+
getSponsor: (domain: string) => Promise<PublicKey>;
|
|
54
|
+
getAddressLookupTables: (addressLookupTableAddress?: string) => Promise<AddressLookupTableAccount[] | undefined>;
|
|
55
|
+
};
|
|
56
|
+
export type Connection = ReturnType<typeof createSessionConnection>;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSessionConnection = exports.TransactionResultType = exports.DEFAULT_PAYMASTER = exports.DEFAULT_RPC = exports.Network = void 0;
|
|
4
|
+
const compat_1 = require("@solana/compat");
|
|
5
|
+
const kit_1 = require("@solana/kit");
|
|
6
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
7
|
+
const zod_1 = require("zod");
|
|
8
|
+
var Network;
|
|
9
|
+
(function (Network) {
|
|
10
|
+
Network[Network["Testnet"] = 0] = "Testnet";
|
|
11
|
+
Network[Network["Mainnet"] = 1] = "Mainnet";
|
|
12
|
+
})(Network || (exports.Network = Network = {}));
|
|
13
|
+
exports.DEFAULT_RPC = {
|
|
14
|
+
[Network.Testnet]: "https://testnet.fogo.io",
|
|
15
|
+
[Network.Mainnet]: "https://mainnet.fogo.io",
|
|
16
|
+
};
|
|
17
|
+
exports.DEFAULT_PAYMASTER = {
|
|
18
|
+
[Network.Testnet]: "https://paymaster.fogo.io",
|
|
19
|
+
[Network.Mainnet]: "https://paymaster.dourolabs.app",
|
|
20
|
+
};
|
|
21
|
+
const DEFAULT_ADDRESS_LOOKUP_TABLE_ADDRESS = {
|
|
22
|
+
[Network.Testnet]: "B8cUjJMqaWWTNNSTXBmeptjWswwCH1gTSCRYv4nu7kJW",
|
|
23
|
+
[Network.Mainnet]: undefined,
|
|
24
|
+
};
|
|
25
|
+
var TransactionResultType;
|
|
26
|
+
(function (TransactionResultType) {
|
|
27
|
+
TransactionResultType[TransactionResultType["Success"] = 0] = "Success";
|
|
28
|
+
TransactionResultType[TransactionResultType["Failed"] = 1] = "Failed";
|
|
29
|
+
})(TransactionResultType || (exports.TransactionResultType = TransactionResultType = {}));
|
|
30
|
+
const TransactionResult = {
|
|
31
|
+
Success: (signature) => ({
|
|
32
|
+
type: TransactionResultType.Success,
|
|
33
|
+
signature,
|
|
34
|
+
}),
|
|
35
|
+
Failed: (signature, error) => ({
|
|
36
|
+
type: TransactionResultType.Failed,
|
|
37
|
+
signature,
|
|
38
|
+
error,
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
const createSessionConnection = (options) => {
|
|
42
|
+
// For some reason, typescript is unable to narrow this type even though it's
|
|
43
|
+
// obvious that `rpc` can only be `undefined` if `network` is defined. I
|
|
44
|
+
// don't like the non-null assertion, but here we can guarantee it's safe (and
|
|
45
|
+
// typescript really should be able to narrow this...)
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
47
|
+
const rpcUrl = (options.rpc ?? exports.DEFAULT_RPC[options.network]).toString();
|
|
48
|
+
const rpc = (0, kit_1.createSolanaRpc)(rpcUrl);
|
|
49
|
+
const connection = new web3_js_1.Connection(rpcUrl, "confirmed");
|
|
50
|
+
return {
|
|
51
|
+
rpc,
|
|
52
|
+
connection,
|
|
53
|
+
sendToPaymaster: async (domain, sponsor, addressLookupTables, sessionKey, instructions) => {
|
|
54
|
+
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
55
|
+
const transaction = await buildTransaction(latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables);
|
|
56
|
+
return sendToPaymaster(options, domain, transaction);
|
|
57
|
+
},
|
|
58
|
+
getSponsor: (domain) => getSponsor(options, domain),
|
|
59
|
+
getAddressLookupTables: (addressLookupTableAddress) => getAddressLookupTables(options, connection, addressLookupTableAddress),
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
exports.createSessionConnection = createSessionConnection;
|
|
63
|
+
const sendToPaymaster = async (options, domain, transaction) => {
|
|
64
|
+
if (options.sendToPaymaster === undefined) {
|
|
65
|
+
const url = new URL("/api/sponsor_and_send", options.paymaster ?? exports.DEFAULT_PAYMASTER[options.network]);
|
|
66
|
+
url.searchParams.set("domain", domain);
|
|
67
|
+
const response = await fetch(url, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: {
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify({
|
|
73
|
+
transaction: (0, kit_1.getBase64EncodedWireTransaction)(transaction),
|
|
74
|
+
}),
|
|
75
|
+
});
|
|
76
|
+
if (response.status === 200) {
|
|
77
|
+
return sponsorAndSendResponseSchema.parse(await response.json());
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
throw new PaymasterResponseError(response.status, await response.text());
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
return options.sendToPaymaster(transaction);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const buildTransaction = async (latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables) => {
|
|
88
|
+
const sessionKeySigner = sessionKey
|
|
89
|
+
? await (0, kit_1.createSignerFromKeyPair)(sessionKey)
|
|
90
|
+
: undefined;
|
|
91
|
+
if (Array.isArray(instructions)) {
|
|
92
|
+
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
|
|
93
|
+
? (0, compat_1.fromLegacyTransactionInstruction)(instruction)
|
|
94
|
+
: instruction), tx), (tx) => (0, kit_1.compressTransactionMessageUsingAddressLookupTables)(tx, Object.fromEntries(addressLookupTables?.map((table) => [
|
|
95
|
+
(0, compat_1.fromLegacyPublicKey)(table.key),
|
|
96
|
+
table.state.addresses.map((address) => (0, compat_1.fromLegacyPublicKey)(address)),
|
|
97
|
+
]) ?? [])), (tx) => sessionKeySigner === undefined
|
|
98
|
+
? tx
|
|
99
|
+
: (0, kit_1.addSignersToTransactionMessage)([sessionKeySigner], tx)));
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const tx = instructions instanceof web3_js_1.VersionedTransaction
|
|
103
|
+
? (0, compat_1.fromVersionedTransaction)(instructions) // VersionedTransaction has a lifetime so it's fine to cast it so we can call partiallySignTransaction
|
|
104
|
+
: instructions;
|
|
105
|
+
return sessionKey === undefined
|
|
106
|
+
? tx
|
|
107
|
+
: (0, kit_1.partiallySignTransaction)([sessionKey], tx);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const sponsorAndSendResponseSchema = zod_1.z
|
|
111
|
+
.discriminatedUnion("type", [
|
|
112
|
+
zod_1.z.object({
|
|
113
|
+
type: zod_1.z.literal("success"),
|
|
114
|
+
signature: zod_1.z.string(),
|
|
115
|
+
}),
|
|
116
|
+
zod_1.z.object({
|
|
117
|
+
type: zod_1.z.literal("failed"),
|
|
118
|
+
signature: zod_1.z.string(),
|
|
119
|
+
error: zod_1.z.object({
|
|
120
|
+
InstructionError: zod_1.z.tuple([zod_1.z.number(), zod_1.z.unknown()]),
|
|
121
|
+
}),
|
|
122
|
+
}),
|
|
123
|
+
])
|
|
124
|
+
.transform((data) => {
|
|
125
|
+
return data.type === "success"
|
|
126
|
+
? TransactionResult.Success(data.signature)
|
|
127
|
+
: TransactionResult.Failed(data.signature, data.error);
|
|
128
|
+
});
|
|
129
|
+
const getSponsor = async (options, domain) => {
|
|
130
|
+
if (options.sponsor === undefined) {
|
|
131
|
+
const url = new URL("/api/sponsor_pubkey", options.paymaster ?? exports.DEFAULT_PAYMASTER[options.network]);
|
|
132
|
+
url.searchParams.set("domain", domain);
|
|
133
|
+
const response = await fetch(url);
|
|
134
|
+
if (response.status === 200) {
|
|
135
|
+
return new web3_js_1.PublicKey(zod_1.z.string().parse(await response.text()));
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
throw new PaymasterResponseError(response.status, await response.text());
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
return options.sponsor;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const getAddressLookupTables = async (options, connection, addressLookupTableAddress) => {
|
|
146
|
+
const altAddress = addressLookupTableAddress ??
|
|
147
|
+
(options.network === undefined
|
|
148
|
+
? undefined
|
|
149
|
+
: DEFAULT_ADDRESS_LOOKUP_TABLE_ADDRESS[options.network]);
|
|
150
|
+
if (altAddress) {
|
|
151
|
+
const addressLookupTableResult = await connection.getAddressLookupTable(new web3_js_1.PublicKey(altAddress));
|
|
152
|
+
return addressLookupTableResult.value
|
|
153
|
+
? [addressLookupTableResult.value]
|
|
154
|
+
: undefined;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
class PaymasterResponseError extends Error {
|
|
161
|
+
constructor(statusCode, message) {
|
|
162
|
+
super(`Paymaster sent a ${statusCode.toString()} response: ${message}`);
|
|
163
|
+
this.name = "PaymasterResponseError";
|
|
164
|
+
}
|
|
165
|
+
}
|
package/cjs/context.d.ts
CHANGED
|
@@ -1,40 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { Connection
|
|
3
|
-
import { PublicKey, TransactionInstruction, VersionedTransaction } from "@solana/web3.js";
|
|
4
|
-
export type SessionContext = {
|
|
5
|
-
chainId: string;
|
|
6
|
-
connection: Connection;
|
|
7
|
-
payer: PublicKey;
|
|
8
|
-
domain: string;
|
|
9
|
-
sendTransaction: (sessionKey: CryptoKeyPair | undefined, instructions: (TransactionInstruction | Instruction)[] | VersionedTransaction | (Transaction & TransactionWithLifetime)) => Promise<TransactionResult>;
|
|
10
|
-
};
|
|
11
|
-
export declare enum TransactionResultType {
|
|
12
|
-
Success = 0,
|
|
13
|
-
Failed = 1
|
|
14
|
-
}
|
|
15
|
-
declare const TransactionResult: {
|
|
16
|
-
Success: (signature: string) => {
|
|
17
|
-
type: TransactionResultType.Success;
|
|
18
|
-
signature: string;
|
|
19
|
-
};
|
|
20
|
-
Failed: (signature: string, error: TransactionError) => {
|
|
21
|
-
type: TransactionResultType.Failed;
|
|
22
|
-
signature: string;
|
|
23
|
-
error: TransactionError;
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
export type TransactionResult = ReturnType<(typeof TransactionResult)[keyof typeof TransactionResult]>;
|
|
1
|
+
import { Connection as Web3Connection } from "@solana/web3.js";
|
|
2
|
+
import type { Connection } from "./connection.js";
|
|
27
3
|
export declare const createSessionContext: (options: {
|
|
28
4
|
connection: Connection;
|
|
29
5
|
addressLookupTableAddress?: string | undefined;
|
|
30
6
|
domain?: string | undefined;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
export {};
|
|
7
|
+
}) => Promise<{
|
|
8
|
+
chainId: string;
|
|
9
|
+
domain: string;
|
|
10
|
+
payer: import("@solana/web3.js").PublicKey;
|
|
11
|
+
connection: Web3Connection;
|
|
12
|
+
rpc: import("@solana/kit").Rpc<import("@solana/kit").RequestAirdropApi & import("@solana/kit").GetAccountInfoApi & import("@solana/kit").GetBalanceApi & import("@solana/kit").GetBlockApi & import("@solana/kit").GetBlockCommitmentApi & import("@solana/kit").GetBlockHeightApi & import("@solana/kit").GetBlockProductionApi & import("@solana/kit").GetBlocksApi & import("@solana/kit").GetBlocksWithLimitApi & import("@solana/kit").GetBlockTimeApi & import("@solana/kit").GetClusterNodesApi & import("@solana/kit").GetEpochInfoApi & import("@solana/kit").GetEpochScheduleApi & import("@solana/kit").GetFeeForMessageApi & import("@solana/kit").GetFirstAvailableBlockApi & import("@solana/kit").GetGenesisHashApi & import("@solana/kit").GetHealthApi & import("@solana/kit").GetHighestSnapshotSlotApi & import("@solana/kit").GetIdentityApi & import("@solana/kit").GetInflationGovernorApi & import("@solana/kit").GetInflationRateApi & import("@solana/kit").GetInflationRewardApi & import("@solana/kit").GetLargestAccountsApi & import("@solana/kit").GetLatestBlockhashApi & import("@solana/kit").GetLeaderScheduleApi & import("@solana/kit").GetMaxRetransmitSlotApi & import("@solana/kit").GetMaxShredInsertSlotApi & import("@solana/kit").GetMinimumBalanceForRentExemptionApi & import("@solana/kit").GetMultipleAccountsApi & import("@solana/kit").GetProgramAccountsApi & import("@solana/kit").GetRecentPerformanceSamplesApi & import("@solana/kit").GetRecentPrioritizationFeesApi & import("@solana/kit").GetSignaturesForAddressApi & import("@solana/kit").GetSignatureStatusesApi & import("@solana/kit").GetSlotApi & import("@solana/kit").GetSlotLeaderApi & import("@solana/kit").GetSlotLeadersApi & import("@solana/kit").GetStakeMinimumDelegationApi & import("@solana/kit").GetSupplyApi & import("@solana/kit").GetTokenAccountBalanceApi & import("@solana/kit").GetTokenAccountsByDelegateApi & import("@solana/kit").GetTokenAccountsByOwnerApi & import("@solana/kit").GetTokenLargestAccountsApi & import("@solana/kit").GetTokenSupplyApi & import("@solana/kit").GetTransactionApi & import("@solana/kit").GetTransactionCountApi & import("@solana/kit").GetVersionApi & import("@solana/kit").GetVoteAccountsApi & import("@solana/kit").IsBlockhashValidApi & import("@solana/kit").MinimumLedgerSlotApi & import("@solana/kit").SendTransactionApi & import("@solana/kit").SimulateTransactionApi>;
|
|
13
|
+
sendTransaction: (sessionKey: CryptoKeyPair | undefined, instructions: Parameters<typeof options.connection.sendToPaymaster>[4]) => Promise<import("./connection.js").TransactionResult>;
|
|
14
|
+
}>;
|
|
15
|
+
export type SessionContext = Awaited<ReturnType<typeof createSessionContext>>;
|
package/cjs/context.js
CHANGED
|
@@ -1,137 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createSessionContext =
|
|
3
|
+
exports.createSessionContext = void 0;
|
|
4
4
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
5
5
|
const sessions_idls_1 = require("@fogo/sessions-idls");
|
|
6
|
-
const compat_1 = require("@solana/compat");
|
|
7
|
-
const kit_1 = require("@solana/kit");
|
|
8
6
|
const web3_js_1 = require("@solana/web3.js");
|
|
9
|
-
const zod_1 = require("zod");
|
|
10
7
|
// eslint-disable-next-line unicorn/no-typeof-undefined
|
|
11
8
|
const IS_BROWSER = typeof globalThis.window !== "undefined";
|
|
12
|
-
const DEFAULT_PAYMASTER = "https://paymaster.fogo.io";
|
|
13
|
-
const DEFAULT_ADDRESS_LOOKUP_TABLE_ADDRESS = "B8cUjJMqaWWTNNSTXBmeptjWswwCH1gTSCRYv4nu7kJW";
|
|
14
|
-
var TransactionResultType;
|
|
15
|
-
(function (TransactionResultType) {
|
|
16
|
-
TransactionResultType[TransactionResultType["Success"] = 0] = "Success";
|
|
17
|
-
TransactionResultType[TransactionResultType["Failed"] = 1] = "Failed";
|
|
18
|
-
})(TransactionResultType || (exports.TransactionResultType = TransactionResultType = {}));
|
|
19
|
-
const TransactionResult = {
|
|
20
|
-
Success: (signature) => ({
|
|
21
|
-
type: TransactionResultType.Success,
|
|
22
|
-
signature,
|
|
23
|
-
}),
|
|
24
|
-
Failed: (signature, error) => ({
|
|
25
|
-
type: TransactionResultType.Failed,
|
|
26
|
-
signature,
|
|
27
|
-
error,
|
|
28
|
-
}),
|
|
29
|
-
};
|
|
30
9
|
const createSessionContext = async (options) => {
|
|
31
|
-
const addressLookupTables = await
|
|
10
|
+
const addressLookupTables = await options.connection.getAddressLookupTables(options.addressLookupTableAddress);
|
|
32
11
|
const domain = getDomain(options.domain);
|
|
33
|
-
const sponsor = await getSponsor(
|
|
12
|
+
const sponsor = await options.connection.getSponsor(domain);
|
|
34
13
|
return {
|
|
35
|
-
|
|
36
|
-
payer: sponsor,
|
|
37
|
-
chainId: await fetchChainId(options.connection),
|
|
14
|
+
chainId: await fetchChainId(options.connection.connection),
|
|
38
15
|
domain: getDomain(options.domain),
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
},
|
|
16
|
+
payer: sponsor,
|
|
17
|
+
connection: options.connection.connection,
|
|
18
|
+
rpc: options.connection.rpc,
|
|
19
|
+
sendTransaction: (sessionKey, instructions) => options.connection.sendToPaymaster(domain, sponsor, addressLookupTables, sessionKey, instructions),
|
|
44
20
|
};
|
|
45
21
|
};
|
|
46
22
|
exports.createSessionContext = createSessionContext;
|
|
47
|
-
const buildTransaction = async (latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables) => {
|
|
48
|
-
const sessionKeySigner = sessionKey
|
|
49
|
-
? await (0, kit_1.createSignerFromKeyPair)(sessionKey)
|
|
50
|
-
: undefined;
|
|
51
|
-
if (Array.isArray(instructions)) {
|
|
52
|
-
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
|
|
53
|
-
? (0, compat_1.fromLegacyTransactionInstruction)(instruction)
|
|
54
|
-
: instruction), tx), (tx) => (0, kit_1.compressTransactionMessageUsingAddressLookupTables)(tx, Object.fromEntries(addressLookupTables?.map((table) => [
|
|
55
|
-
(0, compat_1.fromLegacyPublicKey)(table.key),
|
|
56
|
-
table.state.addresses.map((address) => (0, compat_1.fromLegacyPublicKey)(address)),
|
|
57
|
-
]) ?? [])), (tx) => sessionKeySigner === undefined
|
|
58
|
-
? tx
|
|
59
|
-
: (0, kit_1.addSignersToTransactionMessage)([sessionKeySigner], tx)));
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
const tx = instructions instanceof web3_js_1.VersionedTransaction
|
|
63
|
-
? (0, compat_1.fromVersionedTransaction)(instructions) // VersionedTransaction has a lifetime so it's fine to cast it so we can call partiallySignTransaction
|
|
64
|
-
: instructions;
|
|
65
|
-
return sessionKey === undefined
|
|
66
|
-
? tx
|
|
67
|
-
: (0, kit_1.partiallySignTransaction)([sessionKey], tx);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
const getSponsor = async (options, domain) => {
|
|
71
|
-
if (options.sponsor === undefined) {
|
|
72
|
-
const url = new URL("/api/sponsor_pubkey", options.paymaster ?? DEFAULT_PAYMASTER);
|
|
73
|
-
url.searchParams.set("domain", domain);
|
|
74
|
-
const response = await fetch(url);
|
|
75
|
-
if (response.status === 200) {
|
|
76
|
-
return new web3_js_1.PublicKey(zod_1.z.string().parse(await response.text()));
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
throw new PaymasterResponseError(response.status, await response.text());
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
return options.sponsor;
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
const sponsorAndSendResponseSchema = zod_1.z
|
|
87
|
-
.discriminatedUnion("type", [
|
|
88
|
-
zod_1.z.object({
|
|
89
|
-
type: zod_1.z.literal("success"),
|
|
90
|
-
signature: zod_1.z.string(),
|
|
91
|
-
}),
|
|
92
|
-
zod_1.z.object({
|
|
93
|
-
type: zod_1.z.literal("failed"),
|
|
94
|
-
signature: zod_1.z.string(),
|
|
95
|
-
error: zod_1.z.object({
|
|
96
|
-
InstructionError: zod_1.z.tuple([zod_1.z.number(), zod_1.z.unknown()]),
|
|
97
|
-
}),
|
|
98
|
-
}),
|
|
99
|
-
])
|
|
100
|
-
.transform((data) => {
|
|
101
|
-
return data.type === "success"
|
|
102
|
-
? TransactionResult.Success(data.signature)
|
|
103
|
-
: TransactionResult.Failed(data.signature, data.error);
|
|
104
|
-
});
|
|
105
|
-
const sendToPaymaster = async (options, transaction, domain) => {
|
|
106
|
-
if (options.sendToPaymaster === undefined) {
|
|
107
|
-
const url = new URL("/api/sponsor_and_send", options.paymaster ?? DEFAULT_PAYMASTER);
|
|
108
|
-
url.searchParams.set("domain", domain);
|
|
109
|
-
const response = await fetch(url, {
|
|
110
|
-
method: "POST",
|
|
111
|
-
headers: {
|
|
112
|
-
"Content-Type": "application/json",
|
|
113
|
-
},
|
|
114
|
-
body: JSON.stringify({
|
|
115
|
-
transaction: (0, kit_1.getBase64EncodedWireTransaction)(transaction),
|
|
116
|
-
}),
|
|
117
|
-
});
|
|
118
|
-
if (response.status === 200) {
|
|
119
|
-
return sponsorAndSendResponseSchema.parse(await response.json());
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
throw new PaymasterResponseError(response.status, await response.text());
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
return options.sendToPaymaster(transaction);
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
const getAddressLookupTables = async (connection, addressLookupTableAddress = DEFAULT_ADDRESS_LOOKUP_TABLE_ADDRESS) => {
|
|
130
|
-
const addressLookupTableResult = await connection.getAddressLookupTable(new web3_js_1.PublicKey(addressLookupTableAddress));
|
|
131
|
-
return addressLookupTableResult.value
|
|
132
|
-
? [addressLookupTableResult.value]
|
|
133
|
-
: undefined;
|
|
134
|
-
};
|
|
135
23
|
const fetchChainId = async (connection) => {
|
|
136
24
|
const chainIdProgram = new sessions_idls_1.ChainIdProgram(new anchor_1.AnchorProvider(connection, { publicKey: new web3_js_1.Keypair().publicKey }, {})); // We mock the wallet because we don't need to sign anything
|
|
137
25
|
const { chainIdAccount: chainIdAddress } = await chainIdProgram.methods
|
|
@@ -157,12 +45,6 @@ const getDomain = (requestedDomain) => {
|
|
|
157
45
|
return requestedDomain;
|
|
158
46
|
}
|
|
159
47
|
};
|
|
160
|
-
class PaymasterResponseError extends Error {
|
|
161
|
-
constructor(statusCode, message) {
|
|
162
|
-
super(`Paymaster sent a ${statusCode.toString()} response: ${message}`);
|
|
163
|
-
this.name = "PaymasterResponseError";
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
48
|
class NoChainIdAddressError extends Error {
|
|
167
49
|
constructor() {
|
|
168
50
|
super("Failed to derive chain ID address");
|
package/cjs/index.d.ts
CHANGED
|
@@ -2,8 +2,10 @@ import type { Connection, TransactionError } from "@solana/web3.js";
|
|
|
2
2
|
import { PublicKey } from "@solana/web3.js";
|
|
3
3
|
import BN from "bn.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import type {
|
|
6
|
-
|
|
5
|
+
import type { TransactionResult } from "./connection.js";
|
|
6
|
+
import type { SessionContext } from "./context.js";
|
|
7
|
+
export { type SessionContext, createSessionContext } from "./context.js";
|
|
8
|
+
export { type TransactionResult, type Connection, Network, TransactionResultType, createSessionConnection, } from "./connection.js";
|
|
7
9
|
type EstablishSessionOptions = {
|
|
8
10
|
context: SessionContext;
|
|
9
11
|
walletPublicKey: PublicKey;
|
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.sendTransfer = exports.SessionResultType = exports.getDomainRecordAddress = exports.AuthorizedTokens = exports.AuthorizedProgramsType = exports.getSessionAccount = exports.reestablishSession = exports.revokeSession = exports.replaceSession = exports.establishSession = exports.TransactionResultType = exports.createSessionContext = void 0;
|
|
6
|
+
exports.verifyLogInToken = exports.createLogInToken = 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;
|
|
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");
|
|
@@ -17,11 +17,14 @@ const web3_js_1 = require("@solana/web3.js");
|
|
|
17
17
|
const bn_js_1 = __importDefault(require("bn.js"));
|
|
18
18
|
const bs58_1 = __importDefault(require("bs58"));
|
|
19
19
|
const zod_1 = require("zod");
|
|
20
|
-
const
|
|
20
|
+
const connection_js_1 = require("./connection.js");
|
|
21
21
|
const crypto_js_1 = require("./crypto.js");
|
|
22
|
-
var
|
|
23
|
-
Object.defineProperty(exports, "createSessionContext", { enumerable: true, get: function () { return
|
|
24
|
-
|
|
22
|
+
var context_js_1 = require("./context.js");
|
|
23
|
+
Object.defineProperty(exports, "createSessionContext", { enumerable: true, get: function () { return context_js_1.createSessionContext; } });
|
|
24
|
+
var connection_js_2 = require("./connection.js");
|
|
25
|
+
Object.defineProperty(exports, "Network", { enumerable: true, get: function () { return connection_js_2.Network; } });
|
|
26
|
+
Object.defineProperty(exports, "TransactionResultType", { enumerable: true, get: function () { return connection_js_2.TransactionResultType; } });
|
|
27
|
+
Object.defineProperty(exports, "createSessionConnection", { enumerable: true, get: function () { return connection_js_2.createSessionConnection; } });
|
|
25
28
|
const MESSAGE_HEADER = `Fogo Sessions:
|
|
26
29
|
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.
|
|
27
30
|
`;
|
|
@@ -61,13 +64,13 @@ exports.establishSession = establishSession;
|
|
|
61
64
|
const sendSessionEstablishTransaction = async (options, sessionKey, instructions) => {
|
|
62
65
|
const result = await options.context.sendTransaction(sessionKey, instructions);
|
|
63
66
|
switch (result.type) {
|
|
64
|
-
case
|
|
67
|
+
case connection_js_1.TransactionResultType.Success: {
|
|
65
68
|
const session = await createSession(options.context, options.walletPublicKey, sessionKey);
|
|
66
69
|
return session
|
|
67
70
|
? EstablishSessionResult.Success(result.signature, session)
|
|
68
71
|
: EstablishSessionResult.Failed(result.signature, new Error("Transaction succeeded, but the session was not created"));
|
|
69
72
|
}
|
|
70
|
-
case
|
|
73
|
+
case connection_js_1.TransactionResultType.Failed: {
|
|
71
74
|
return EstablishSessionResult.Failed(result.signature, result.error);
|
|
72
75
|
}
|
|
73
76
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Transaction, Instruction, TransactionWithLifetime } from "@solana/kit";
|
|
2
|
+
import type { AddressLookupTableAccount, TransactionError } from "@solana/web3.js";
|
|
3
|
+
import { Connection as Web3Connection, TransactionInstruction, VersionedTransaction, PublicKey } from "@solana/web3.js";
|
|
4
|
+
export declare enum Network {
|
|
5
|
+
Testnet = 0,
|
|
6
|
+
Mainnet = 1
|
|
7
|
+
}
|
|
8
|
+
export declare const DEFAULT_RPC: {
|
|
9
|
+
0: string;
|
|
10
|
+
1: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const DEFAULT_PAYMASTER: {
|
|
13
|
+
0: string;
|
|
14
|
+
1: string;
|
|
15
|
+
};
|
|
16
|
+
export declare enum TransactionResultType {
|
|
17
|
+
Success = 0,
|
|
18
|
+
Failed = 1
|
|
19
|
+
}
|
|
20
|
+
declare const TransactionResult: {
|
|
21
|
+
Success: (signature: string) => {
|
|
22
|
+
type: TransactionResultType.Success;
|
|
23
|
+
signature: string;
|
|
24
|
+
};
|
|
25
|
+
Failed: (signature: string, error: TransactionError) => {
|
|
26
|
+
type: TransactionResultType.Failed;
|
|
27
|
+
signature: string;
|
|
28
|
+
error: TransactionError;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
export type TransactionResult = ReturnType<(typeof TransactionResult)[keyof typeof TransactionResult]>;
|
|
32
|
+
export declare const createSessionConnection: (options: {
|
|
33
|
+
network: Network;
|
|
34
|
+
rpc?: string | URL | undefined;
|
|
35
|
+
paymaster?: undefined;
|
|
36
|
+
sendToPaymaster?: undefined;
|
|
37
|
+
sponsor?: undefined;
|
|
38
|
+
} | ({
|
|
39
|
+
network?: Network | undefined;
|
|
40
|
+
rpc: string | URL;
|
|
41
|
+
} & ({
|
|
42
|
+
paymaster: string | URL;
|
|
43
|
+
sendToPaymaster?: undefined;
|
|
44
|
+
sponsor?: undefined;
|
|
45
|
+
} | {
|
|
46
|
+
paymaster?: undefined;
|
|
47
|
+
sendToPaymaster: (transaction: Transaction) => Promise<TransactionResult>;
|
|
48
|
+
sponsor: PublicKey;
|
|
49
|
+
}))) => {
|
|
50
|
+
rpc: import("@solana/kit").Rpc<import("@solana/kit").RequestAirdropApi & import("@solana/kit").GetAccountInfoApi & import("@solana/kit").GetBalanceApi & import("@solana/kit").GetBlockApi & import("@solana/kit").GetBlockCommitmentApi & import("@solana/kit").GetBlockHeightApi & import("@solana/kit").GetBlockProductionApi & import("@solana/kit").GetBlocksApi & import("@solana/kit").GetBlocksWithLimitApi & import("@solana/kit").GetBlockTimeApi & import("@solana/kit").GetClusterNodesApi & import("@solana/kit").GetEpochInfoApi & import("@solana/kit").GetEpochScheduleApi & import("@solana/kit").GetFeeForMessageApi & import("@solana/kit").GetFirstAvailableBlockApi & import("@solana/kit").GetGenesisHashApi & import("@solana/kit").GetHealthApi & import("@solana/kit").GetHighestSnapshotSlotApi & import("@solana/kit").GetIdentityApi & import("@solana/kit").GetInflationGovernorApi & import("@solana/kit").GetInflationRateApi & import("@solana/kit").GetInflationRewardApi & import("@solana/kit").GetLargestAccountsApi & import("@solana/kit").GetLatestBlockhashApi & import("@solana/kit").GetLeaderScheduleApi & import("@solana/kit").GetMaxRetransmitSlotApi & import("@solana/kit").GetMaxShredInsertSlotApi & import("@solana/kit").GetMinimumBalanceForRentExemptionApi & import("@solana/kit").GetMultipleAccountsApi & import("@solana/kit").GetProgramAccountsApi & import("@solana/kit").GetRecentPerformanceSamplesApi & import("@solana/kit").GetRecentPrioritizationFeesApi & import("@solana/kit").GetSignaturesForAddressApi & import("@solana/kit").GetSignatureStatusesApi & import("@solana/kit").GetSlotApi & import("@solana/kit").GetSlotLeaderApi & import("@solana/kit").GetSlotLeadersApi & import("@solana/kit").GetStakeMinimumDelegationApi & import("@solana/kit").GetSupplyApi & import("@solana/kit").GetTokenAccountBalanceApi & import("@solana/kit").GetTokenAccountsByDelegateApi & import("@solana/kit").GetTokenAccountsByOwnerApi & import("@solana/kit").GetTokenLargestAccountsApi & import("@solana/kit").GetTokenSupplyApi & import("@solana/kit").GetTransactionApi & import("@solana/kit").GetTransactionCountApi & import("@solana/kit").GetVersionApi & import("@solana/kit").GetVoteAccountsApi & import("@solana/kit").IsBlockhashValidApi & import("@solana/kit").MinimumLedgerSlotApi & import("@solana/kit").SendTransactionApi & import("@solana/kit").SimulateTransactionApi>;
|
|
51
|
+
connection: Web3Connection;
|
|
52
|
+
sendToPaymaster: (domain: string, sponsor: PublicKey, addressLookupTables: AddressLookupTableAccount[] | undefined, sessionKey: CryptoKeyPair | undefined, instructions: (TransactionInstruction | Instruction)[] | VersionedTransaction | (Transaction & TransactionWithLifetime)) => Promise<TransactionResult>;
|
|
53
|
+
getSponsor: (domain: string) => Promise<PublicKey>;
|
|
54
|
+
getAddressLookupTables: (addressLookupTableAddress?: string) => Promise<AddressLookupTableAccount[] | undefined>;
|
|
55
|
+
};
|
|
56
|
+
export type Connection = ReturnType<typeof createSessionConnection>;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { fromLegacyPublicKey, fromLegacyTransactionInstruction, fromVersionedTransaction, } from "@solana/compat";
|
|
2
|
+
import { createSolanaRpc, getBase64EncodedWireTransaction, createTransactionMessage, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, partiallySignTransactionMessageWithSigners, pipe, addSignersToTransactionMessage, compressTransactionMessageUsingAddressLookupTables, createSignerFromKeyPair, partiallySignTransaction, } from "@solana/kit";
|
|
3
|
+
import { Connection as Web3Connection, TransactionInstruction, VersionedTransaction, PublicKey, } from "@solana/web3.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
export var Network;
|
|
6
|
+
(function (Network) {
|
|
7
|
+
Network[Network["Testnet"] = 0] = "Testnet";
|
|
8
|
+
Network[Network["Mainnet"] = 1] = "Mainnet";
|
|
9
|
+
})(Network || (Network = {}));
|
|
10
|
+
export const DEFAULT_RPC = {
|
|
11
|
+
[Network.Testnet]: "https://testnet.fogo.io",
|
|
12
|
+
[Network.Mainnet]: "https://mainnet.fogo.io",
|
|
13
|
+
};
|
|
14
|
+
export const DEFAULT_PAYMASTER = {
|
|
15
|
+
[Network.Testnet]: "https://paymaster.fogo.io",
|
|
16
|
+
[Network.Mainnet]: "https://paymaster.dourolabs.app",
|
|
17
|
+
};
|
|
18
|
+
const DEFAULT_ADDRESS_LOOKUP_TABLE_ADDRESS = {
|
|
19
|
+
[Network.Testnet]: "B8cUjJMqaWWTNNSTXBmeptjWswwCH1gTSCRYv4nu7kJW",
|
|
20
|
+
[Network.Mainnet]: undefined,
|
|
21
|
+
};
|
|
22
|
+
export var TransactionResultType;
|
|
23
|
+
(function (TransactionResultType) {
|
|
24
|
+
TransactionResultType[TransactionResultType["Success"] = 0] = "Success";
|
|
25
|
+
TransactionResultType[TransactionResultType["Failed"] = 1] = "Failed";
|
|
26
|
+
})(TransactionResultType || (TransactionResultType = {}));
|
|
27
|
+
const TransactionResult = {
|
|
28
|
+
Success: (signature) => ({
|
|
29
|
+
type: TransactionResultType.Success,
|
|
30
|
+
signature,
|
|
31
|
+
}),
|
|
32
|
+
Failed: (signature, error) => ({
|
|
33
|
+
type: TransactionResultType.Failed,
|
|
34
|
+
signature,
|
|
35
|
+
error,
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
export const createSessionConnection = (options) => {
|
|
39
|
+
// For some reason, typescript is unable to narrow this type even though it's
|
|
40
|
+
// obvious that `rpc` can only be `undefined` if `network` is defined. I
|
|
41
|
+
// don't like the non-null assertion, but here we can guarantee it's safe (and
|
|
42
|
+
// typescript really should be able to narrow this...)
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
44
|
+
const rpcUrl = (options.rpc ?? DEFAULT_RPC[options.network]).toString();
|
|
45
|
+
const rpc = createSolanaRpc(rpcUrl);
|
|
46
|
+
const connection = new Web3Connection(rpcUrl, "confirmed");
|
|
47
|
+
return {
|
|
48
|
+
rpc,
|
|
49
|
+
connection,
|
|
50
|
+
sendToPaymaster: async (domain, sponsor, addressLookupTables, sessionKey, instructions) => {
|
|
51
|
+
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
52
|
+
const transaction = await buildTransaction(latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables);
|
|
53
|
+
return sendToPaymaster(options, domain, transaction);
|
|
54
|
+
},
|
|
55
|
+
getSponsor: (domain) => getSponsor(options, domain),
|
|
56
|
+
getAddressLookupTables: (addressLookupTableAddress) => getAddressLookupTables(options, connection, addressLookupTableAddress),
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
const sendToPaymaster = async (options, domain, transaction) => {
|
|
60
|
+
if (options.sendToPaymaster === undefined) {
|
|
61
|
+
const url = new URL("/api/sponsor_and_send", options.paymaster ?? DEFAULT_PAYMASTER[options.network]);
|
|
62
|
+
url.searchParams.set("domain", domain);
|
|
63
|
+
const response = await fetch(url, {
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: {
|
|
66
|
+
"Content-Type": "application/json",
|
|
67
|
+
},
|
|
68
|
+
body: JSON.stringify({
|
|
69
|
+
transaction: getBase64EncodedWireTransaction(transaction),
|
|
70
|
+
}),
|
|
71
|
+
});
|
|
72
|
+
if (response.status === 200) {
|
|
73
|
+
return sponsorAndSendResponseSchema.parse(await response.json());
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
throw new PaymasterResponseError(response.status, await response.text());
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return options.sendToPaymaster(transaction);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const buildTransaction = async (latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables) => {
|
|
84
|
+
const sessionKeySigner = sessionKey
|
|
85
|
+
? await createSignerFromKeyPair(sessionKey)
|
|
86
|
+
: undefined;
|
|
87
|
+
if (Array.isArray(instructions)) {
|
|
88
|
+
return partiallySignTransactionMessageWithSigners(pipe(createTransactionMessage({ version: 0 }), (tx) => setTransactionMessageFeePayer(fromLegacyPublicKey(sponsor), tx), (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) => appendTransactionMessageInstructions(instructions.map((instruction) => instruction instanceof TransactionInstruction
|
|
89
|
+
? fromLegacyTransactionInstruction(instruction)
|
|
90
|
+
: instruction), tx), (tx) => compressTransactionMessageUsingAddressLookupTables(tx, Object.fromEntries(addressLookupTables?.map((table) => [
|
|
91
|
+
fromLegacyPublicKey(table.key),
|
|
92
|
+
table.state.addresses.map((address) => fromLegacyPublicKey(address)),
|
|
93
|
+
]) ?? [])), (tx) => sessionKeySigner === undefined
|
|
94
|
+
? tx
|
|
95
|
+
: addSignersToTransactionMessage([sessionKeySigner], tx)));
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const tx = instructions instanceof VersionedTransaction
|
|
99
|
+
? fromVersionedTransaction(instructions) // VersionedTransaction has a lifetime so it's fine to cast it so we can call partiallySignTransaction
|
|
100
|
+
: instructions;
|
|
101
|
+
return sessionKey === undefined
|
|
102
|
+
? tx
|
|
103
|
+
: partiallySignTransaction([sessionKey], tx);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const sponsorAndSendResponseSchema = z
|
|
107
|
+
.discriminatedUnion("type", [
|
|
108
|
+
z.object({
|
|
109
|
+
type: z.literal("success"),
|
|
110
|
+
signature: z.string(),
|
|
111
|
+
}),
|
|
112
|
+
z.object({
|
|
113
|
+
type: z.literal("failed"),
|
|
114
|
+
signature: z.string(),
|
|
115
|
+
error: z.object({
|
|
116
|
+
InstructionError: z.tuple([z.number(), z.unknown()]),
|
|
117
|
+
}),
|
|
118
|
+
}),
|
|
119
|
+
])
|
|
120
|
+
.transform((data) => {
|
|
121
|
+
return data.type === "success"
|
|
122
|
+
? TransactionResult.Success(data.signature)
|
|
123
|
+
: TransactionResult.Failed(data.signature, data.error);
|
|
124
|
+
});
|
|
125
|
+
const getSponsor = async (options, domain) => {
|
|
126
|
+
if (options.sponsor === undefined) {
|
|
127
|
+
const url = new URL("/api/sponsor_pubkey", options.paymaster ?? DEFAULT_PAYMASTER[options.network]);
|
|
128
|
+
url.searchParams.set("domain", domain);
|
|
129
|
+
const response = await fetch(url);
|
|
130
|
+
if (response.status === 200) {
|
|
131
|
+
return new PublicKey(z.string().parse(await response.text()));
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
throw new PaymasterResponseError(response.status, await response.text());
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
return options.sponsor;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const getAddressLookupTables = async (options, connection, addressLookupTableAddress) => {
|
|
142
|
+
const altAddress = addressLookupTableAddress ??
|
|
143
|
+
(options.network === undefined
|
|
144
|
+
? undefined
|
|
145
|
+
: DEFAULT_ADDRESS_LOOKUP_TABLE_ADDRESS[options.network]);
|
|
146
|
+
if (altAddress) {
|
|
147
|
+
const addressLookupTableResult = await connection.getAddressLookupTable(new PublicKey(altAddress));
|
|
148
|
+
return addressLookupTableResult.value
|
|
149
|
+
? [addressLookupTableResult.value]
|
|
150
|
+
: undefined;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
class PaymasterResponseError extends Error {
|
|
157
|
+
constructor(statusCode, message) {
|
|
158
|
+
super(`Paymaster sent a ${statusCode.toString()} response: ${message}`);
|
|
159
|
+
this.name = "PaymasterResponseError";
|
|
160
|
+
}
|
|
161
|
+
}
|
package/esm/context.d.ts
CHANGED
|
@@ -1,40 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { Connection
|
|
3
|
-
import { PublicKey, TransactionInstruction, VersionedTransaction } from "@solana/web3.js";
|
|
4
|
-
export type SessionContext = {
|
|
5
|
-
chainId: string;
|
|
6
|
-
connection: Connection;
|
|
7
|
-
payer: PublicKey;
|
|
8
|
-
domain: string;
|
|
9
|
-
sendTransaction: (sessionKey: CryptoKeyPair | undefined, instructions: (TransactionInstruction | Instruction)[] | VersionedTransaction | (Transaction & TransactionWithLifetime)) => Promise<TransactionResult>;
|
|
10
|
-
};
|
|
11
|
-
export declare enum TransactionResultType {
|
|
12
|
-
Success = 0,
|
|
13
|
-
Failed = 1
|
|
14
|
-
}
|
|
15
|
-
declare const TransactionResult: {
|
|
16
|
-
Success: (signature: string) => {
|
|
17
|
-
type: TransactionResultType.Success;
|
|
18
|
-
signature: string;
|
|
19
|
-
};
|
|
20
|
-
Failed: (signature: string, error: TransactionError) => {
|
|
21
|
-
type: TransactionResultType.Failed;
|
|
22
|
-
signature: string;
|
|
23
|
-
error: TransactionError;
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
export type TransactionResult = ReturnType<(typeof TransactionResult)[keyof typeof TransactionResult]>;
|
|
1
|
+
import { Connection as Web3Connection } from "@solana/web3.js";
|
|
2
|
+
import type { Connection } from "./connection.js";
|
|
27
3
|
export declare const createSessionContext: (options: {
|
|
28
4
|
connection: Connection;
|
|
29
5
|
addressLookupTableAddress?: string | undefined;
|
|
30
6
|
domain?: string | undefined;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
export {};
|
|
7
|
+
}) => Promise<{
|
|
8
|
+
chainId: string;
|
|
9
|
+
domain: string;
|
|
10
|
+
payer: import("@solana/web3.js").PublicKey;
|
|
11
|
+
connection: Web3Connection;
|
|
12
|
+
rpc: import("@solana/kit").Rpc<import("@solana/kit").RequestAirdropApi & import("@solana/kit").GetAccountInfoApi & import("@solana/kit").GetBalanceApi & import("@solana/kit").GetBlockApi & import("@solana/kit").GetBlockCommitmentApi & import("@solana/kit").GetBlockHeightApi & import("@solana/kit").GetBlockProductionApi & import("@solana/kit").GetBlocksApi & import("@solana/kit").GetBlocksWithLimitApi & import("@solana/kit").GetBlockTimeApi & import("@solana/kit").GetClusterNodesApi & import("@solana/kit").GetEpochInfoApi & import("@solana/kit").GetEpochScheduleApi & import("@solana/kit").GetFeeForMessageApi & import("@solana/kit").GetFirstAvailableBlockApi & import("@solana/kit").GetGenesisHashApi & import("@solana/kit").GetHealthApi & import("@solana/kit").GetHighestSnapshotSlotApi & import("@solana/kit").GetIdentityApi & import("@solana/kit").GetInflationGovernorApi & import("@solana/kit").GetInflationRateApi & import("@solana/kit").GetInflationRewardApi & import("@solana/kit").GetLargestAccountsApi & import("@solana/kit").GetLatestBlockhashApi & import("@solana/kit").GetLeaderScheduleApi & import("@solana/kit").GetMaxRetransmitSlotApi & import("@solana/kit").GetMaxShredInsertSlotApi & import("@solana/kit").GetMinimumBalanceForRentExemptionApi & import("@solana/kit").GetMultipleAccountsApi & import("@solana/kit").GetProgramAccountsApi & import("@solana/kit").GetRecentPerformanceSamplesApi & import("@solana/kit").GetRecentPrioritizationFeesApi & import("@solana/kit").GetSignaturesForAddressApi & import("@solana/kit").GetSignatureStatusesApi & import("@solana/kit").GetSlotApi & import("@solana/kit").GetSlotLeaderApi & import("@solana/kit").GetSlotLeadersApi & import("@solana/kit").GetStakeMinimumDelegationApi & import("@solana/kit").GetSupplyApi & import("@solana/kit").GetTokenAccountBalanceApi & import("@solana/kit").GetTokenAccountsByDelegateApi & import("@solana/kit").GetTokenAccountsByOwnerApi & import("@solana/kit").GetTokenLargestAccountsApi & import("@solana/kit").GetTokenSupplyApi & import("@solana/kit").GetTransactionApi & import("@solana/kit").GetTransactionCountApi & import("@solana/kit").GetVersionApi & import("@solana/kit").GetVoteAccountsApi & import("@solana/kit").IsBlockhashValidApi & import("@solana/kit").MinimumLedgerSlotApi & import("@solana/kit").SendTransactionApi & import("@solana/kit").SimulateTransactionApi>;
|
|
13
|
+
sendTransaction: (sessionKey: CryptoKeyPair | undefined, instructions: Parameters<typeof options.connection.sendToPaymaster>[4]) => Promise<import("./connection.js").TransactionResult>;
|
|
14
|
+
}>;
|
|
15
|
+
export type SessionContext = Awaited<ReturnType<typeof createSessionContext>>;
|
package/esm/context.js
CHANGED
|
@@ -1,133 +1,21 @@
|
|
|
1
1
|
import { AnchorProvider } from "@coral-xyz/anchor";
|
|
2
2
|
import { ChainIdProgram } from "@fogo/sessions-idls";
|
|
3
|
-
import {
|
|
4
|
-
import { createTransactionMessage, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, getBase64EncodedWireTransaction, partiallySignTransactionMessageWithSigners, pipe, createSolanaRpc, addSignersToTransactionMessage, compressTransactionMessageUsingAddressLookupTables, createSignerFromKeyPair, partiallySignTransaction, } from "@solana/kit";
|
|
5
|
-
import { PublicKey, Keypair, TransactionInstruction, VersionedTransaction, } from "@solana/web3.js";
|
|
6
|
-
import { z } from "zod";
|
|
3
|
+
import { Connection as Web3Connection, Keypair } from "@solana/web3.js";
|
|
7
4
|
// eslint-disable-next-line unicorn/no-typeof-undefined
|
|
8
5
|
const IS_BROWSER = typeof globalThis.window !== "undefined";
|
|
9
|
-
const DEFAULT_PAYMASTER = "https://paymaster.fogo.io";
|
|
10
|
-
const DEFAULT_ADDRESS_LOOKUP_TABLE_ADDRESS = "B8cUjJMqaWWTNNSTXBmeptjWswwCH1gTSCRYv4nu7kJW";
|
|
11
|
-
export var TransactionResultType;
|
|
12
|
-
(function (TransactionResultType) {
|
|
13
|
-
TransactionResultType[TransactionResultType["Success"] = 0] = "Success";
|
|
14
|
-
TransactionResultType[TransactionResultType["Failed"] = 1] = "Failed";
|
|
15
|
-
})(TransactionResultType || (TransactionResultType = {}));
|
|
16
|
-
const TransactionResult = {
|
|
17
|
-
Success: (signature) => ({
|
|
18
|
-
type: TransactionResultType.Success,
|
|
19
|
-
signature,
|
|
20
|
-
}),
|
|
21
|
-
Failed: (signature, error) => ({
|
|
22
|
-
type: TransactionResultType.Failed,
|
|
23
|
-
signature,
|
|
24
|
-
error,
|
|
25
|
-
}),
|
|
26
|
-
};
|
|
27
6
|
export const createSessionContext = async (options) => {
|
|
28
|
-
const addressLookupTables = await
|
|
7
|
+
const addressLookupTables = await options.connection.getAddressLookupTables(options.addressLookupTableAddress);
|
|
29
8
|
const domain = getDomain(options.domain);
|
|
30
|
-
const sponsor = await getSponsor(
|
|
9
|
+
const sponsor = await options.connection.getSponsor(domain);
|
|
31
10
|
return {
|
|
32
|
-
|
|
33
|
-
payer: sponsor,
|
|
34
|
-
chainId: await fetchChainId(options.connection),
|
|
11
|
+
chainId: await fetchChainId(options.connection.connection),
|
|
35
12
|
domain: getDomain(options.domain),
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
},
|
|
13
|
+
payer: sponsor,
|
|
14
|
+
connection: options.connection.connection,
|
|
15
|
+
rpc: options.connection.rpc,
|
|
16
|
+
sendTransaction: (sessionKey, instructions) => options.connection.sendToPaymaster(domain, sponsor, addressLookupTables, sessionKey, instructions),
|
|
41
17
|
};
|
|
42
18
|
};
|
|
43
|
-
const buildTransaction = async (latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables) => {
|
|
44
|
-
const sessionKeySigner = sessionKey
|
|
45
|
-
? await createSignerFromKeyPair(sessionKey)
|
|
46
|
-
: undefined;
|
|
47
|
-
if (Array.isArray(instructions)) {
|
|
48
|
-
return partiallySignTransactionMessageWithSigners(pipe(createTransactionMessage({ version: 0 }), (tx) => setTransactionMessageFeePayer(fromLegacyPublicKey(sponsor), tx), (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) => appendTransactionMessageInstructions(instructions.map((instruction) => instruction instanceof TransactionInstruction
|
|
49
|
-
? fromLegacyTransactionInstruction(instruction)
|
|
50
|
-
: instruction), tx), (tx) => compressTransactionMessageUsingAddressLookupTables(tx, Object.fromEntries(addressLookupTables?.map((table) => [
|
|
51
|
-
fromLegacyPublicKey(table.key),
|
|
52
|
-
table.state.addresses.map((address) => fromLegacyPublicKey(address)),
|
|
53
|
-
]) ?? [])), (tx) => sessionKeySigner === undefined
|
|
54
|
-
? tx
|
|
55
|
-
: addSignersToTransactionMessage([sessionKeySigner], tx)));
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
const tx = instructions instanceof VersionedTransaction
|
|
59
|
-
? fromVersionedTransaction(instructions) // VersionedTransaction has a lifetime so it's fine to cast it so we can call partiallySignTransaction
|
|
60
|
-
: instructions;
|
|
61
|
-
return sessionKey === undefined
|
|
62
|
-
? tx
|
|
63
|
-
: partiallySignTransaction([sessionKey], tx);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
const getSponsor = async (options, domain) => {
|
|
67
|
-
if (options.sponsor === undefined) {
|
|
68
|
-
const url = new URL("/api/sponsor_pubkey", options.paymaster ?? DEFAULT_PAYMASTER);
|
|
69
|
-
url.searchParams.set("domain", domain);
|
|
70
|
-
const response = await fetch(url);
|
|
71
|
-
if (response.status === 200) {
|
|
72
|
-
return new PublicKey(z.string().parse(await response.text()));
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
throw new PaymasterResponseError(response.status, await response.text());
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
return options.sponsor;
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
const sponsorAndSendResponseSchema = z
|
|
83
|
-
.discriminatedUnion("type", [
|
|
84
|
-
z.object({
|
|
85
|
-
type: z.literal("success"),
|
|
86
|
-
signature: z.string(),
|
|
87
|
-
}),
|
|
88
|
-
z.object({
|
|
89
|
-
type: z.literal("failed"),
|
|
90
|
-
signature: z.string(),
|
|
91
|
-
error: z.object({
|
|
92
|
-
InstructionError: z.tuple([z.number(), z.unknown()]),
|
|
93
|
-
}),
|
|
94
|
-
}),
|
|
95
|
-
])
|
|
96
|
-
.transform((data) => {
|
|
97
|
-
return data.type === "success"
|
|
98
|
-
? TransactionResult.Success(data.signature)
|
|
99
|
-
: TransactionResult.Failed(data.signature, data.error);
|
|
100
|
-
});
|
|
101
|
-
const sendToPaymaster = async (options, transaction, domain) => {
|
|
102
|
-
if (options.sendToPaymaster === undefined) {
|
|
103
|
-
const url = new URL("/api/sponsor_and_send", options.paymaster ?? DEFAULT_PAYMASTER);
|
|
104
|
-
url.searchParams.set("domain", domain);
|
|
105
|
-
const response = await fetch(url, {
|
|
106
|
-
method: "POST",
|
|
107
|
-
headers: {
|
|
108
|
-
"Content-Type": "application/json",
|
|
109
|
-
},
|
|
110
|
-
body: JSON.stringify({
|
|
111
|
-
transaction: getBase64EncodedWireTransaction(transaction),
|
|
112
|
-
}),
|
|
113
|
-
});
|
|
114
|
-
if (response.status === 200) {
|
|
115
|
-
return sponsorAndSendResponseSchema.parse(await response.json());
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
throw new PaymasterResponseError(response.status, await response.text());
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
return options.sendToPaymaster(transaction);
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
const getAddressLookupTables = async (connection, addressLookupTableAddress = DEFAULT_ADDRESS_LOOKUP_TABLE_ADDRESS) => {
|
|
126
|
-
const addressLookupTableResult = await connection.getAddressLookupTable(new PublicKey(addressLookupTableAddress));
|
|
127
|
-
return addressLookupTableResult.value
|
|
128
|
-
? [addressLookupTableResult.value]
|
|
129
|
-
: undefined;
|
|
130
|
-
};
|
|
131
19
|
const fetchChainId = async (connection) => {
|
|
132
20
|
const chainIdProgram = new ChainIdProgram(new AnchorProvider(connection, { publicKey: new Keypair().publicKey }, {})); // We mock the wallet because we don't need to sign anything
|
|
133
21
|
const { chainIdAccount: chainIdAddress } = await chainIdProgram.methods
|
|
@@ -153,12 +41,6 @@ const getDomain = (requestedDomain) => {
|
|
|
153
41
|
return requestedDomain;
|
|
154
42
|
}
|
|
155
43
|
};
|
|
156
|
-
class PaymasterResponseError extends Error {
|
|
157
|
-
constructor(statusCode, message) {
|
|
158
|
-
super(`Paymaster sent a ${statusCode.toString()} response: ${message}`);
|
|
159
|
-
this.name = "PaymasterResponseError";
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
44
|
class NoChainIdAddressError extends Error {
|
|
163
45
|
constructor() {
|
|
164
46
|
super("Failed to derive chain ID address");
|
package/esm/index.d.ts
CHANGED
|
@@ -2,8 +2,10 @@ import type { Connection, TransactionError } from "@solana/web3.js";
|
|
|
2
2
|
import { PublicKey } from "@solana/web3.js";
|
|
3
3
|
import BN from "bn.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import type {
|
|
6
|
-
|
|
5
|
+
import type { TransactionResult } from "./connection.js";
|
|
6
|
+
import type { SessionContext } from "./context.js";
|
|
7
|
+
export { type SessionContext, createSessionContext } from "./context.js";
|
|
8
|
+
export { type TransactionResult, type Connection, Network, TransactionResultType, createSessionConnection, } from "./connection.js";
|
|
7
9
|
type EstablishSessionOptions = {
|
|
8
10
|
context: SessionContext;
|
|
9
11
|
walletPublicKey: PublicKey;
|
package/esm/index.js
CHANGED
|
@@ -11,9 +11,10 @@ import { Ed25519Program, PublicKey } from "@solana/web3.js";
|
|
|
11
11
|
import BN from "bn.js";
|
|
12
12
|
import bs58 from "bs58";
|
|
13
13
|
import { z } from "zod";
|
|
14
|
-
import { TransactionResultType } from "./
|
|
14
|
+
import { TransactionResultType } from "./connection.js";
|
|
15
15
|
import { importKey, signMessageWithKey, verifyMessageWithKey, } from "./crypto.js";
|
|
16
|
-
export { createSessionContext
|
|
16
|
+
export { createSessionContext } from "./context.js";
|
|
17
|
+
export { Network, TransactionResultType, createSessionConnection, } from "./connection.js";
|
|
17
18
|
const MESSAGE_HEADER = `Fogo Sessions:
|
|
18
19
|
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.
|
|
19
20
|
`;
|