@fogo/sessions-sdk 0.0.16 → 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/{adapter.js → connection.js} +77 -89
- package/cjs/context.d.ts +15 -0
- package/cjs/context.js +59 -0
- package/cjs/index.d.ts +10 -8
- package/cjs/index.js +36 -33
- package/esm/connection.d.ts +57 -0
- package/esm/{adapter.js → connection.js} +77 -89
- package/esm/context.d.ts +15 -0
- package/esm/context.js +55 -0
- package/esm/index.d.ts +10 -8
- package/esm/index.js +29 -28
- package/package.json +2 -2
- package/cjs/adapter.d.ts +0 -37
- package/esm/adapter.d.ts +0 -37
|
@@ -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 {};
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const anchor_1 = require("@coral-xyz/anchor");
|
|
5
|
-
const sessions_idls_1 = require("@fogo/sessions-idls");
|
|
3
|
+
exports.createSessionConnection = exports.TransactionResultType = exports.DEFAULT_PAYMASTER = exports.DEFAULT_RPC = exports.Network = void 0;
|
|
6
4
|
const compat_1 = require("@solana/compat");
|
|
7
5
|
const kit_1 = require("@solana/kit");
|
|
8
6
|
const web3_js_1 = require("@solana/web3.js");
|
|
9
7
|
const zod_1 = require("zod");
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
+
};
|
|
14
25
|
var TransactionResultType;
|
|
15
26
|
(function (TransactionResultType) {
|
|
16
27
|
TransactionResultType[TransactionResultType["Success"] = 0] = "Success";
|
|
@@ -27,23 +38,52 @@ const TransactionResult = {
|
|
|
27
38
|
error,
|
|
28
39
|
}),
|
|
29
40
|
};
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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");
|
|
34
50
|
return {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
domain: getDomain(options.domain),
|
|
39
|
-
sendTransaction: async (sessionKey, instructions) => {
|
|
40
|
-
const rpc = (0, kit_1.createSolanaRpc)(options.connection.rpcEndpoint);
|
|
51
|
+
rpc,
|
|
52
|
+
connection,
|
|
53
|
+
sendToPaymaster: async (domain, sponsor, addressLookupTables, sessionKey, instructions) => {
|
|
41
54
|
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
42
|
-
|
|
55
|
+
const transaction = await buildTransaction(latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables);
|
|
56
|
+
return sendToPaymaster(options, domain, transaction);
|
|
43
57
|
},
|
|
58
|
+
getSponsor: (domain) => getSponsor(options, domain),
|
|
59
|
+
getAddressLookupTables: (addressLookupTableAddress) => getAddressLookupTables(options, connection, addressLookupTableAddress),
|
|
44
60
|
};
|
|
45
61
|
};
|
|
46
|
-
exports.
|
|
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
|
+
};
|
|
47
87
|
const buildTransaction = async (latestBlockhash, sessionKey, sponsor, instructions, addressLookupTables) => {
|
|
48
88
|
const sessionKeySigner = sessionKey
|
|
49
89
|
? await (0, kit_1.createSignerFromKeyPair)(sessionKey)
|
|
@@ -67,22 +107,6 @@ const buildTransaction = async (latestBlockhash, sessionKey, sponsor, instructio
|
|
|
67
107
|
: (0, kit_1.partiallySignTransaction)([sessionKey], tx);
|
|
68
108
|
}
|
|
69
109
|
};
|
|
70
|
-
const getSponsor = async (options, domain) => {
|
|
71
|
-
if ("sponsor" in options) {
|
|
72
|
-
return options.sponsor;
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
const url = new URL("/api/sponsor_pubkey", options.paymaster ?? DEFAULT_PAYMASTER);
|
|
76
|
-
url.searchParams.set("domain", domain);
|
|
77
|
-
const response = await fetch(url);
|
|
78
|
-
if (response.status === 200) {
|
|
79
|
-
return new web3_js_1.PublicKey(zod_1.z.string().parse(await response.text()));
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
throw new PaymasterResponseError(response.status, await response.text());
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
110
|
const sponsorAndSendResponseSchema = zod_1.z
|
|
87
111
|
.discriminatedUnion("type", [
|
|
88
112
|
zod_1.z.object({
|
|
@@ -102,59 +126,35 @@ const sponsorAndSendResponseSchema = zod_1.z
|
|
|
102
126
|
? TransactionResult.Success(data.signature)
|
|
103
127
|
: TransactionResult.Failed(data.signature, data.error);
|
|
104
128
|
});
|
|
105
|
-
const
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
const url = new URL("/api/sponsor_and_send", options.paymaster ?? DEFAULT_PAYMASTER);
|
|
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]);
|
|
111
132
|
url.searchParams.set("domain", domain);
|
|
112
|
-
const response = await fetch(url
|
|
113
|
-
method: "POST",
|
|
114
|
-
headers: {
|
|
115
|
-
"Content-Type": "application/json",
|
|
116
|
-
},
|
|
117
|
-
body: JSON.stringify({
|
|
118
|
-
transaction: (0, kit_1.getBase64EncodedWireTransaction)(transaction),
|
|
119
|
-
}),
|
|
120
|
-
});
|
|
133
|
+
const response = await fetch(url);
|
|
121
134
|
if (response.status === 200) {
|
|
122
|
-
return
|
|
135
|
+
return new web3_js_1.PublicKey(zod_1.z.string().parse(await response.text()));
|
|
123
136
|
}
|
|
124
137
|
else {
|
|
125
138
|
throw new PaymasterResponseError(response.status, await response.text());
|
|
126
139
|
}
|
|
127
140
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const addressLookupTableResult = await connection.getAddressLookupTable(new web3_js_1.PublicKey(addressLookupTableAddress));
|
|
131
|
-
return addressLookupTableResult.value
|
|
132
|
-
? [addressLookupTableResult.value]
|
|
133
|
-
: undefined;
|
|
134
|
-
};
|
|
135
|
-
const fetchChainId = async (connection) => {
|
|
136
|
-
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
|
-
const { chainIdAccount: chainIdAddress } = await chainIdProgram.methods
|
|
138
|
-
.set("")
|
|
139
|
-
.pubkeys(); // We use Anchor to derive the chain ID address, not caring about the actual argument of `set`
|
|
140
|
-
if (chainIdAddress === undefined) {
|
|
141
|
-
throw new NoChainIdAddressError();
|
|
141
|
+
else {
|
|
142
|
+
return options.sponsor;
|
|
142
143
|
}
|
|
143
|
-
const chainId = await chainIdProgram.account.chainId.fetch(chainIdAddress);
|
|
144
|
-
return chainId.chainId;
|
|
145
144
|
};
|
|
146
|
-
const
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
155
|
}
|
|
156
156
|
else {
|
|
157
|
-
return
|
|
157
|
+
return;
|
|
158
158
|
}
|
|
159
159
|
};
|
|
160
160
|
class PaymasterResponseError extends Error {
|
|
@@ -163,15 +163,3 @@ class PaymasterResponseError extends Error {
|
|
|
163
163
|
this.name = "PaymasterResponseError";
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
|
-
class NoChainIdAddressError extends Error {
|
|
167
|
-
constructor() {
|
|
168
|
-
super("Failed to derive chain ID address");
|
|
169
|
-
this.name = "NoChainIdAddressError";
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
class DomainRequiredError extends Error {
|
|
173
|
-
constructor() {
|
|
174
|
-
super("On platforms where the origin cannot be determined, you must pass a domain to create a session.");
|
|
175
|
-
this.name = "DomainRequiredError";
|
|
176
|
-
}
|
|
177
|
-
}
|
package/cjs/context.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Connection as Web3Connection } from "@solana/web3.js";
|
|
2
|
+
import type { Connection } from "./connection.js";
|
|
3
|
+
export declare const createSessionContext: (options: {
|
|
4
|
+
connection: Connection;
|
|
5
|
+
addressLookupTableAddress?: string | undefined;
|
|
6
|
+
domain?: string | undefined;
|
|
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
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSessionContext = void 0;
|
|
4
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
5
|
+
const sessions_idls_1 = require("@fogo/sessions-idls");
|
|
6
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
7
|
+
// eslint-disable-next-line unicorn/no-typeof-undefined
|
|
8
|
+
const IS_BROWSER = typeof globalThis.window !== "undefined";
|
|
9
|
+
const createSessionContext = async (options) => {
|
|
10
|
+
const addressLookupTables = await options.connection.getAddressLookupTables(options.addressLookupTableAddress);
|
|
11
|
+
const domain = getDomain(options.domain);
|
|
12
|
+
const sponsor = await options.connection.getSponsor(domain);
|
|
13
|
+
return {
|
|
14
|
+
chainId: await fetchChainId(options.connection.connection),
|
|
15
|
+
domain: getDomain(options.domain),
|
|
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),
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
exports.createSessionContext = createSessionContext;
|
|
23
|
+
const fetchChainId = async (connection) => {
|
|
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
|
|
25
|
+
const { chainIdAccount: chainIdAddress } = await chainIdProgram.methods
|
|
26
|
+
.set("")
|
|
27
|
+
.pubkeys(); // We use Anchor to derive the chain ID address, not caring about the actual argument of `set`
|
|
28
|
+
if (chainIdAddress === undefined) {
|
|
29
|
+
throw new NoChainIdAddressError();
|
|
30
|
+
}
|
|
31
|
+
const chainId = await chainIdProgram.account.chainId.fetch(chainIdAddress);
|
|
32
|
+
return chainId.chainId;
|
|
33
|
+
};
|
|
34
|
+
const getDomain = (requestedDomain) => {
|
|
35
|
+
const detectedDomain = IS_BROWSER ? globalThis.location.origin : undefined;
|
|
36
|
+
if (requestedDomain === undefined) {
|
|
37
|
+
if (detectedDomain === undefined) {
|
|
38
|
+
throw new DomainRequiredError();
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
return detectedDomain;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
return requestedDomain;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
class NoChainIdAddressError extends Error {
|
|
49
|
+
constructor() {
|
|
50
|
+
super("Failed to derive chain ID address");
|
|
51
|
+
this.name = "NoChainIdAddressError";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
class DomainRequiredError extends Error {
|
|
55
|
+
constructor() {
|
|
56
|
+
super("On platforms where the origin cannot be determined, you must pass a domain to create a session.");
|
|
57
|
+
this.name = "DomainRequiredError";
|
|
58
|
+
}
|
|
59
|
+
}
|
package/cjs/index.d.ts
CHANGED
|
@@ -2,10 +2,12 @@ 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;
|
|
10
12
|
signMessage: (message: Uint8Array) => Promise<Uint8Array>;
|
|
11
13
|
expires: Date;
|
|
@@ -19,7 +21,7 @@ type EstablishSessionOptions = {
|
|
|
19
21
|
});
|
|
20
22
|
export declare const establishSession: (options: EstablishSessionOptions) => Promise<EstablishSessionResult>;
|
|
21
23
|
export declare const replaceSession: (options: {
|
|
22
|
-
|
|
24
|
+
context: SessionContext;
|
|
23
25
|
session: Session;
|
|
24
26
|
signMessage: (message: Uint8Array) => Promise<Uint8Array>;
|
|
25
27
|
expires: Date;
|
|
@@ -31,10 +33,10 @@ export declare const replaceSession: (options: {
|
|
|
31
33
|
unlimited: true;
|
|
32
34
|
})) => Promise<EstablishSessionResult>;
|
|
33
35
|
export declare const revokeSession: (options: {
|
|
34
|
-
|
|
36
|
+
context: SessionContext;
|
|
35
37
|
session: Session;
|
|
36
38
|
}) => Promise<TransactionResult | undefined>;
|
|
37
|
-
export declare const reestablishSession: (
|
|
39
|
+
export declare const reestablishSession: (context: SessionContext, walletPublicKey: PublicKey, sessionKey: CryptoKeyPair) => Promise<Session | undefined>;
|
|
38
40
|
export declare const getSessionAccount: (connection: Connection, sessionPublicKey: PublicKey) => Promise<{
|
|
39
41
|
authorizedPrograms: {
|
|
40
42
|
type: AuthorizedProgramsType.All;
|
|
@@ -1302,11 +1304,11 @@ export type Session = {
|
|
|
1302
1304
|
sessionKey: CryptoKeyPair;
|
|
1303
1305
|
walletPublicKey: PublicKey;
|
|
1304
1306
|
payer: PublicKey;
|
|
1305
|
-
sendTransaction: (instructions: Parameters<
|
|
1307
|
+
sendTransaction: (instructions: Parameters<SessionContext["sendTransaction"]>[1]) => Promise<TransactionResult>;
|
|
1306
1308
|
sessionInfo: NonNullable<z.infer<typeof sessionInfoSchema>>;
|
|
1307
1309
|
};
|
|
1308
1310
|
type SendTransferOptions = {
|
|
1309
|
-
|
|
1311
|
+
context: SessionContext;
|
|
1310
1312
|
walletPublicKey: PublicKey;
|
|
1311
1313
|
signMessage: (message: Uint8Array) => Promise<Uint8Array>;
|
|
1312
1314
|
mint: 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.
|
|
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, "
|
|
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
|
`;
|
|
@@ -44,7 +47,7 @@ const establishSession = async (options) => {
|
|
|
44
47
|
else {
|
|
45
48
|
const filteredLimits = new Map(options.limits?.entries().filter(([, amount]) => amount > 0n));
|
|
46
49
|
const tokenInfo = filteredLimits.size > 0
|
|
47
|
-
? await getTokenInfo(options.
|
|
50
|
+
? await getTokenInfo(options.context, filteredLimits)
|
|
48
51
|
: [];
|
|
49
52
|
const [intentInstruction, startSessionInstruction] = await Promise.all([
|
|
50
53
|
buildIntentInstruction(options, sessionKey, tokenInfo),
|
|
@@ -59,15 +62,15 @@ const establishSession = async (options) => {
|
|
|
59
62
|
};
|
|
60
63
|
exports.establishSession = establishSession;
|
|
61
64
|
const sendSessionEstablishTransaction = async (options, sessionKey, instructions) => {
|
|
62
|
-
const result = await options.
|
|
65
|
+
const result = await options.context.sendTransaction(sessionKey, instructions);
|
|
63
66
|
switch (result.type) {
|
|
64
|
-
case
|
|
65
|
-
const session = await createSession(options.
|
|
67
|
+
case connection_js_1.TransactionResultType.Success: {
|
|
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
|
}
|
|
@@ -79,14 +82,14 @@ const replaceSession = async (options) => (0, exports.establishSession)({
|
|
|
79
82
|
exports.replaceSession = replaceSession;
|
|
80
83
|
const revokeSession = async (options) => {
|
|
81
84
|
if (options.session.sessionInfo.minor >= 2) {
|
|
82
|
-
const instruction = await new sessions_idls_1.SessionManagerProgram(new anchor_1.AnchorProvider(options.
|
|
85
|
+
const instruction = await new sessions_idls_1.SessionManagerProgram(new anchor_1.AnchorProvider(options.context.connection, {}, {})).methods
|
|
83
86
|
.revokeSession()
|
|
84
87
|
.accounts({
|
|
85
88
|
sponsor: options.session.sessionInfo.sponsor,
|
|
86
89
|
session: options.session.sessionPublicKey,
|
|
87
90
|
})
|
|
88
91
|
.instruction();
|
|
89
|
-
return options.
|
|
92
|
+
return options.context.sendTransaction(options.session.sessionKey, [
|
|
90
93
|
instruction,
|
|
91
94
|
]);
|
|
92
95
|
}
|
|
@@ -95,7 +98,7 @@ const revokeSession = async (options) => {
|
|
|
95
98
|
}
|
|
96
99
|
};
|
|
97
100
|
exports.revokeSession = revokeSession;
|
|
98
|
-
const reestablishSession = async (
|
|
101
|
+
const reestablishSession = async (context, walletPublicKey, sessionKey) => createSession(context, walletPublicKey, sessionKey);
|
|
99
102
|
exports.reestablishSession = reestablishSession;
|
|
100
103
|
const getSessionAccount = async (connection, sessionPublicKey) => {
|
|
101
104
|
const result = await connection.getAccountInfo(sessionPublicKey, "confirmed");
|
|
@@ -104,17 +107,17 @@ const getSessionAccount = async (connection, sessionPublicKey) => {
|
|
|
104
107
|
: sessionInfoSchema.parse(new anchor_1.BorshAccountsCoder(sessions_idls_1.SessionManagerIdl).decode("Session", result.data));
|
|
105
108
|
};
|
|
106
109
|
exports.getSessionAccount = getSessionAccount;
|
|
107
|
-
const createSession = async (
|
|
110
|
+
const createSession = async (context, walletPublicKey, sessionKey) => {
|
|
108
111
|
const sessionPublicKey = new web3_js_1.PublicKey(await (0, kit_1.getAddressFromPublicKey)(sessionKey.publicKey));
|
|
109
|
-
const sessionInfo = await (0, exports.getSessionAccount)(
|
|
112
|
+
const sessionInfo = await (0, exports.getSessionAccount)(context.connection, sessionPublicKey);
|
|
110
113
|
return sessionInfo === undefined
|
|
111
114
|
? undefined
|
|
112
115
|
: {
|
|
113
116
|
sessionPublicKey,
|
|
114
117
|
walletPublicKey,
|
|
115
118
|
sessionKey,
|
|
116
|
-
payer:
|
|
117
|
-
sendTransaction: (instructions) =>
|
|
119
|
+
payer: context.payer,
|
|
120
|
+
sendTransaction: (instructions) => context.sendTransaction(sessionKey, instructions),
|
|
118
121
|
sessionInfo,
|
|
119
122
|
};
|
|
120
123
|
};
|
|
@@ -299,13 +302,13 @@ const SymbolOrMint = {
|
|
|
299
302
|
mint,
|
|
300
303
|
}),
|
|
301
304
|
};
|
|
302
|
-
const getTokenInfo = async (
|
|
303
|
-
const umi = (0, umi_bundle_defaults_1.createUmi)(
|
|
305
|
+
const getTokenInfo = async (context, limits) => {
|
|
306
|
+
const umi = (0, umi_bundle_defaults_1.createUmi)(context.connection.rpcEndpoint);
|
|
304
307
|
return Promise.all(limits.entries().map(async ([mint, amount]) => {
|
|
305
308
|
const metaplexMint = (0, umi_1.publicKey)(mint.toBase58());
|
|
306
309
|
const metadataAddress = (0, mpl_token_metadata_1.findMetadataPda)(umi, { mint: metaplexMint })[0];
|
|
307
310
|
const [mintInfo, metadata] = await Promise.all([
|
|
308
|
-
(0, spl_token_1.getMint)(
|
|
311
|
+
(0, spl_token_1.getMint)(context.connection, mint),
|
|
309
312
|
(0, mpl_token_metadata_1.safeFetchMetadata)(umi, metadataAddress),
|
|
310
313
|
]);
|
|
311
314
|
return {
|
|
@@ -351,8 +354,8 @@ const addOffchainMessagePrefixToMessageIfNeeded = async (walletPublicKey, signat
|
|
|
351
354
|
};
|
|
352
355
|
const buildIntentInstruction = async (options, sessionKey, tokens) => {
|
|
353
356
|
const message = await buildMessage({
|
|
354
|
-
chainId: options.
|
|
355
|
-
domain: options.
|
|
357
|
+
chainId: options.context.chainId,
|
|
358
|
+
domain: options.context.domain,
|
|
356
359
|
sessionKey,
|
|
357
360
|
expires: options.expires,
|
|
358
361
|
tokens,
|
|
@@ -417,19 +420,19 @@ const amountToString = (amount, decimals) => {
|
|
|
417
420
|
...(decimalTruncated === "" ? [] : [".", decimalTruncated]),
|
|
418
421
|
].join("");
|
|
419
422
|
};
|
|
420
|
-
const buildCreateAssociatedTokenAccountInstructions = (options, tokens) => tokens.map(({ mint }) => (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(options.
|
|
423
|
+
const buildCreateAssociatedTokenAccountInstructions = (options, tokens) => tokens.map(({ mint }) => (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(options.context.payer, (0, spl_token_1.getAssociatedTokenAddressSync)(mint, options.walletPublicKey), options.walletPublicKey, mint));
|
|
421
424
|
const getDomainRecordAddress = (domain) => {
|
|
422
425
|
const hash = (0, sha2_1.sha256)(domain);
|
|
423
426
|
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("domain-record"), hash], new web3_js_1.PublicKey(sessions_idls_1.DomainRegistryIdl.address))[0];
|
|
424
427
|
};
|
|
425
428
|
exports.getDomainRecordAddress = getDomainRecordAddress;
|
|
426
429
|
const buildStartSessionInstruction = async (options, sessionKey, tokens) => {
|
|
427
|
-
const instruction = new sessions_idls_1.SessionManagerProgram(new anchor_1.AnchorProvider(options.
|
|
430
|
+
const instruction = new sessions_idls_1.SessionManagerProgram(new anchor_1.AnchorProvider(options.context.connection, {}, {})).methods
|
|
428
431
|
.startSession()
|
|
429
432
|
.accounts({
|
|
430
|
-
sponsor: options.
|
|
433
|
+
sponsor: options.context.payer,
|
|
431
434
|
session: await (0, kit_1.getAddressFromPublicKey)(sessionKey.publicKey),
|
|
432
|
-
domainRegistry: (0, exports.getDomainRecordAddress)(options.
|
|
435
|
+
domainRegistry: (0, exports.getDomainRecordAddress)(options.context.domain),
|
|
433
436
|
});
|
|
434
437
|
return tokens === undefined
|
|
435
438
|
? instruction.instruction()
|
|
@@ -480,14 +483,14 @@ Signing this intent will transfer the tokens as described below.
|
|
|
480
483
|
const sendTransfer = async (options) => {
|
|
481
484
|
const sourceAta = (0, spl_token_1.getAssociatedTokenAddressSync)(options.mint, options.walletPublicKey);
|
|
482
485
|
const destinationAta = (0, spl_token_1.getAssociatedTokenAddressSync)(options.mint, options.recipient);
|
|
483
|
-
const program = new sessions_idls_1.IntentTransferProgram(new anchor_1.AnchorProvider(options.
|
|
484
|
-
const umi = (0, umi_bundle_defaults_1.createUmi)(options.
|
|
486
|
+
const program = new sessions_idls_1.IntentTransferProgram(new anchor_1.AnchorProvider(options.context.connection, {}, {}));
|
|
487
|
+
const umi = (0, umi_bundle_defaults_1.createUmi)(options.context.connection.rpcEndpoint);
|
|
485
488
|
const metaplexMint = (0, umi_1.publicKey)(options.mint.toBase58());
|
|
486
489
|
const metadataAddress = (0, mpl_token_metadata_1.findMetadataPda)(umi, { mint: metaplexMint })[0];
|
|
487
490
|
const metadata = await (0, mpl_token_metadata_1.safeFetchMetadata)(umi, metadataAddress);
|
|
488
491
|
const symbol = metadata?.symbol ?? undefined;
|
|
489
|
-
return options.
|
|
490
|
-
(0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(options.
|
|
492
|
+
return options.context.sendTransaction(undefined, [
|
|
493
|
+
(0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(options.context.payer, destinationAta, options.recipient, options.mint),
|
|
491
494
|
await buildTransferIntentInstruction(program, options, symbol),
|
|
492
495
|
await program.methods
|
|
493
496
|
.sendTokens()
|
|
@@ -495,7 +498,7 @@ const sendTransfer = async (options) => {
|
|
|
495
498
|
destination: destinationAta,
|
|
496
499
|
mint: options.mint,
|
|
497
500
|
source: sourceAta,
|
|
498
|
-
sponsor: options.
|
|
501
|
+
sponsor: options.context.payer,
|
|
499
502
|
// eslint-disable-next-line unicorn/no-null
|
|
500
503
|
metadata: symbol === undefined ? null : new web3_js_1.PublicKey(metadataAddress),
|
|
501
504
|
})
|
|
@@ -506,13 +509,13 @@ exports.sendTransfer = sendTransfer;
|
|
|
506
509
|
const buildTransferIntentInstruction = async (program, options, symbol) => {
|
|
507
510
|
const [nonce, { decimals }] = await Promise.all([
|
|
508
511
|
getNonce(program, options.walletPublicKey),
|
|
509
|
-
(0, spl_token_1.getMint)(options.
|
|
512
|
+
(0, spl_token_1.getMint)(options.context.connection, options.mint),
|
|
510
513
|
]);
|
|
511
514
|
const message = new TextEncoder().encode([
|
|
512
515
|
TRANSFER_MESSAGE_HEADER,
|
|
513
516
|
serializeKV({
|
|
514
517
|
version: `${CURRENT_INTENT_TRANSFER_MAJOR}.${CURRENT_INTENT_TRANSFER_MINOR}`,
|
|
515
|
-
chain_id: options.
|
|
518
|
+
chain_id: options.context.chainId,
|
|
516
519
|
token: symbol ?? options.mint.toBase58(),
|
|
517
520
|
amount: amountToString(options.amount, decimals),
|
|
518
521
|
recipient: options.recipient.toBase58(),
|