@5ive-tech/sdk 1.1.21 → 1.1.22

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.
@@ -9,21 +9,56 @@ export interface CreateSessionParams {
9
9
  authority: string;
10
10
  delegate: string;
11
11
  targetProgram: string;
12
+ sessionAccount?: string;
12
13
  expiresAtSlot: number;
13
14
  scopeHash: string;
14
15
  bindAccount?: string;
15
16
  nonce?: number;
16
17
  payer?: string;
18
+ rpcLabel?: string;
19
+ schemaPreference?: CreateSessionSchema | 'auto';
17
20
  }
18
21
  export interface RevokeSessionParams {
19
22
  authority: string;
20
23
  delegate: string;
21
24
  targetProgram: string;
22
25
  payer?: string;
26
+ rpcLabel?: string;
23
27
  }
24
28
  export interface CreateSessionCompatResult {
25
29
  signature: string;
26
- schema: 'minimal';
30
+ schema: CreateSessionSchema;
31
+ }
32
+ export type CreateSessionSchema = 'legacy' | 'minimal';
33
+ export interface SessionClientBuildContext {
34
+ operation: 'derive_session' | 'create_session' | 'revoke_session';
35
+ schema?: CreateSessionSchema;
36
+ managerScriptAccount: string;
37
+ vmProgramId: string;
38
+ sessionAddress?: string;
39
+ targetProgram?: string;
40
+ authority?: string;
41
+ delegate?: string;
42
+ rpcLabel?: string;
43
+ }
44
+ export declare class SessionClientBuildError extends Error {
45
+ readonly context: SessionClientBuildContext;
46
+ readonly cause?: unknown;
47
+ constructor(message: string, context: SessionClientBuildContext, cause?: unknown);
48
+ }
49
+ export interface BuildCreateSessionPlanOptions {
50
+ connection?: Connection;
51
+ payer?: PublicKey;
52
+ delegateMinLamports?: number;
53
+ delegateTopupLamports?: number;
54
+ rpcLabel?: string;
55
+ }
56
+ export interface CreateSessionPlan {
57
+ schema: CreateSessionSchema;
58
+ sessionAddress: string;
59
+ createSessionIx: TransactionInstruction;
60
+ createSessionAccountIx: TransactionInstruction | null;
61
+ topupDelegateIx: TransactionInstruction | null;
27
62
  }
28
63
  export declare function scopeHashForFunctions(functionNames: string[]): string;
29
64
  export declare function canonicalSessionManagerScriptAccount(vmProgramId: string): string;
@@ -36,9 +71,13 @@ export declare class SessionClient {
36
71
  });
37
72
  static scopeHashForFunctions(functionNames: string[]): string;
38
73
  static canonicalManagerScriptAccount(vmProgramId: string): string;
74
+ private buildError;
75
+ private createSessionSchemas;
39
76
  deriveSessionAddress(authority: string, delegate: string, targetProgram: string): Promise<string>;
77
+ private buildCreateSessionCore;
40
78
  createSessionIx(params: CreateSessionParams): Promise<TransactionInstruction>;
41
- createSessionWithCompat(params: CreateSessionParams, send: (ix: TransactionInstruction, schema: 'minimal') => Promise<string>): Promise<CreateSessionCompatResult>;
79
+ buildCreateSessionPlan(params: CreateSessionParams, options?: BuildCreateSessionPlanOptions): Promise<CreateSessionPlan>;
80
+ createSessionWithCompat(params: CreateSessionParams, send: (ix: TransactionInstruction, schema: CreateSessionSchema) => Promise<string>): Promise<CreateSessionCompatResult>;
42
81
  revokeSessionIx(params: RevokeSessionParams): Promise<TransactionInstruction>;
43
82
  prepareSessionAccountTx(input: {
44
83
  connection: Connection;
@@ -1,5 +1,13 @@
1
1
  import { PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js';
2
2
  import { FiveProgram } from '../program/FiveProgram.js';
3
+ export class SessionClientBuildError extends Error {
4
+ constructor(message, context, cause) {
5
+ super(message);
6
+ this.name = 'SessionClientBuildError';
7
+ this.context = context;
8
+ this.cause = cause;
9
+ }
10
+ }
3
11
  const SYSTEM_PROGRAM = '11111111111111111111111111111111';
4
12
  const SESSION_MANAGER_ABI_MINIMAL = {
5
13
  name: 'SessionManager',
@@ -36,6 +44,45 @@ const SESSION_MANAGER_ABI_MINIMAL = {
36
44
  },
37
45
  ],
38
46
  };
47
+ const SESSION_MANAGER_ABI_LEGACY = {
48
+ name: 'SessionManager',
49
+ functions: [
50
+ {
51
+ name: 'create_session',
52
+ index: 0,
53
+ parameters: [
54
+ { name: 'session', type: 'Account', is_account: true, attributes: ['mut'] },
55
+ { name: 'authority', type: 'Account', is_account: true, attributes: ['signer'] },
56
+ { name: 'delegate', type: 'Account', is_account: true, attributes: [] },
57
+ { name: 'target_program', type: 'pubkey', is_account: false, attributes: [] },
58
+ { name: 'expires_at_slot', type: 'u64', is_account: false, attributes: [] },
59
+ { name: 'scope_hash', type: 'u64', is_account: false, attributes: [] },
60
+ { name: 'bind_account', type: 'pubkey', is_account: false, attributes: [] },
61
+ { name: 'nonce', type: 'u64', is_account: false, attributes: [] },
62
+ { name: 'manager_script_account', type: 'pubkey', is_account: false, attributes: [] },
63
+ { name: 'manager_code_hash', type: 'pubkey', is_account: false, attributes: [] },
64
+ { name: 'manager_version', type: 'u8', is_account: false, attributes: [] },
65
+ ],
66
+ return_type: null,
67
+ visibility: 'public',
68
+ is_public: true,
69
+ bytecode_offset: 0,
70
+ },
71
+ {
72
+ name: 'revoke_session',
73
+ index: 1,
74
+ parameters: [
75
+ { name: 'session', type: 'Account', is_account: true, attributes: ['mut'] },
76
+ { name: 'authority', type: 'Account', is_account: true, attributes: ['signer'] },
77
+ ],
78
+ return_type: null,
79
+ visibility: 'public',
80
+ is_public: true,
81
+ bytecode_offset: 0,
82
+ },
83
+ ],
84
+ };
85
+ const DEFAULT_CREATE_SESSION_SCHEMA = 'legacy';
39
86
  export function scopeHashForFunctions(functionNames) {
40
87
  const sorted = [...functionNames].sort();
41
88
  let acc = 0n;
@@ -61,67 +108,222 @@ export class SessionClient {
61
108
  static canonicalManagerScriptAccount(vmProgramId) {
62
109
  return canonicalSessionManagerScriptAccount(vmProgramId);
63
110
  }
111
+ buildError(message, context, cause) {
112
+ return new SessionClientBuildError(message, context, cause);
113
+ }
114
+ createSessionSchemas(preference) {
115
+ if (preference === 'minimal')
116
+ return ['minimal'];
117
+ if (preference === 'legacy')
118
+ return ['legacy'];
119
+ return [DEFAULT_CREATE_SESSION_SCHEMA, 'minimal'].filter((schema, index, all) => all.indexOf(schema) === index);
120
+ }
64
121
  async deriveSessionAddress(authority, delegate, targetProgram) {
65
- const [session] = await FiveProgram.fromABI(this.managerScriptAccount, SESSION_MANAGER_ABI_MINIMAL, {
66
- fiveVMProgramId: this.vmProgramId,
67
- }).findAddress(['session', authority, delegate, targetProgram], this.vmProgramId);
68
- return session;
122
+ try {
123
+ const [session] = await FiveProgram.fromABI(this.managerScriptAccount, SESSION_MANAGER_ABI_MINIMAL, {
124
+ fiveVMProgramId: this.vmProgramId,
125
+ }).findAddress(['session', authority, delegate, targetProgram], this.vmProgramId);
126
+ return session;
127
+ }
128
+ catch (error) {
129
+ throw this.buildError('Failed to derive canonical session address', {
130
+ operation: 'derive_session',
131
+ managerScriptAccount: this.managerScriptAccount,
132
+ vmProgramId: this.vmProgramId,
133
+ authority,
134
+ delegate,
135
+ targetProgram,
136
+ }, error);
137
+ }
69
138
  }
70
- async createSessionIx(params) {
71
- const session = await this.deriveSessionAddress(params.authority, params.delegate, params.targetProgram);
72
- const program = FiveProgram.fromABI(this.managerScriptAccount, SESSION_MANAGER_ABI_MINIMAL, {
73
- fiveVMProgramId: this.vmProgramId,
74
- });
75
- const argMap = {
76
- target_program: params.targetProgram,
77
- expires_at_slot: params.expiresAtSlot,
78
- scope_hash: params.scopeHash,
79
- bind_account: params.bindAccount || SYSTEM_PROGRAM,
80
- nonce: params.nonce ?? 0,
81
- };
82
- const builder = program
83
- .function('create_session')
84
- .accounts({
85
- session,
139
+ async buildCreateSessionCore(params, schema) {
140
+ const sessionAddress = await this.deriveSessionAddress(params.authority, params.delegate, params.targetProgram);
141
+ const resolvedSessionAddress = schema === 'legacy' && params.sessionAccount
142
+ ? params.sessionAccount
143
+ : sessionAddress;
144
+ const contextBase = {
145
+ operation: 'create_session',
146
+ schema,
147
+ managerScriptAccount: this.managerScriptAccount,
148
+ vmProgramId: this.vmProgramId,
149
+ sessionAddress: resolvedSessionAddress,
86
150
  authority: params.authority,
87
151
  delegate: params.delegate,
88
- })
89
- .args(argMap);
90
- builder.payer(params.payer || params.authority);
91
- const encoded = await builder.instruction();
92
- return new TransactionInstruction({
93
- programId: new PublicKey(encoded.programId),
94
- keys: encoded.keys.map((k) => ({
95
- pubkey: new PublicKey(k.pubkey),
96
- isSigner: k.isSigner,
97
- isWritable: k.isWritable,
98
- })),
99
- data: Buffer.from(encoded.data, 'base64'),
100
- });
152
+ targetProgram: params.targetProgram,
153
+ rpcLabel: params.rpcLabel,
154
+ };
155
+ try {
156
+ const program = FiveProgram.fromABI(this.managerScriptAccount, schema === 'legacy' ? SESSION_MANAGER_ABI_LEGACY : SESSION_MANAGER_ABI_MINIMAL, {
157
+ fiveVMProgramId: this.vmProgramId,
158
+ });
159
+ const argMap = {
160
+ target_program: params.targetProgram,
161
+ expires_at_slot: params.expiresAtSlot,
162
+ scope_hash: params.scopeHash,
163
+ bind_account: params.bindAccount || SYSTEM_PROGRAM,
164
+ nonce: params.nonce ?? 0,
165
+ };
166
+ if (schema === 'legacy') {
167
+ argMap.manager_script_account = this.managerScriptAccount;
168
+ argMap.manager_code_hash = SYSTEM_PROGRAM;
169
+ argMap.manager_version = 1;
170
+ }
171
+ const builder = program
172
+ .function('create_session')
173
+ .accounts({
174
+ session: resolvedSessionAddress,
175
+ authority: params.authority,
176
+ delegate: params.delegate,
177
+ })
178
+ .args(argMap);
179
+ builder.payer(params.payer || params.authority);
180
+ const encoded = await builder.instruction();
181
+ return {
182
+ schema,
183
+ sessionAddress: resolvedSessionAddress,
184
+ instruction: new TransactionInstruction({
185
+ programId: new PublicKey(encoded.programId),
186
+ keys: encoded.keys.map((k) => ({
187
+ pubkey: new PublicKey(k.pubkey),
188
+ isSigner: k.isSigner,
189
+ isWritable: k.isWritable,
190
+ })),
191
+ data: Buffer.from(encoded.data, 'base64'),
192
+ }),
193
+ };
194
+ }
195
+ catch (error) {
196
+ throw this.buildError('Failed to build create_session instruction', contextBase, error);
197
+ }
198
+ }
199
+ async createSessionIx(params) {
200
+ const schema = this.createSessionSchemas(params.schemaPreference)[0];
201
+ const built = await this.buildCreateSessionCore(params, schema);
202
+ return built.instruction;
203
+ }
204
+ async buildCreateSessionPlan(params, options = {}) {
205
+ const schema = this.createSessionSchemas(params.schemaPreference)[0];
206
+ const built = await this.buildCreateSessionCore(params, schema);
207
+ let createSessionAccountIx = null;
208
+ let topupDelegateIx = null;
209
+ if (options.connection && options.payer && schema === 'legacy' && params.sessionAccount) {
210
+ try {
211
+ const prepared = await this.prepareSessionAccountTx({
212
+ connection: options.connection,
213
+ payer: options.payer,
214
+ sessionAccount: new PublicKey(params.sessionAccount),
215
+ delegate: new PublicKey(params.delegate),
216
+ delegateMinLamports: options.delegateMinLamports,
217
+ delegateTopupLamports: options.delegateTopupLamports,
218
+ });
219
+ createSessionAccountIx = prepared.createIx;
220
+ topupDelegateIx = prepared.topupIx;
221
+ }
222
+ catch (error) {
223
+ throw this.buildError('Failed while building session account setup instructions for create_session', {
224
+ operation: 'create_session',
225
+ schema,
226
+ managerScriptAccount: this.managerScriptAccount,
227
+ vmProgramId: this.vmProgramId,
228
+ sessionAddress: built.sessionAddress,
229
+ authority: params.authority,
230
+ delegate: params.delegate,
231
+ targetProgram: params.targetProgram,
232
+ rpcLabel: options.rpcLabel || params.rpcLabel,
233
+ }, error);
234
+ }
235
+ }
236
+ else if (options.connection &&
237
+ options.payer &&
238
+ options.delegateMinLamports &&
239
+ options.delegateTopupLamports) {
240
+ try {
241
+ const delegateBalance = await options.connection.getBalance(new PublicKey(params.delegate), 'confirmed');
242
+ if (delegateBalance < options.delegateMinLamports) {
243
+ topupDelegateIx = SystemProgram.transfer({
244
+ fromPubkey: options.payer,
245
+ toPubkey: new PublicKey(params.delegate),
246
+ lamports: options.delegateTopupLamports,
247
+ });
248
+ }
249
+ }
250
+ catch (error) {
251
+ throw this.buildError('Failed while building delegate funding instruction for create_session', {
252
+ operation: 'create_session',
253
+ schema,
254
+ managerScriptAccount: this.managerScriptAccount,
255
+ vmProgramId: this.vmProgramId,
256
+ sessionAddress: built.sessionAddress,
257
+ authority: params.authority,
258
+ delegate: params.delegate,
259
+ targetProgram: params.targetProgram,
260
+ rpcLabel: options.rpcLabel || params.rpcLabel,
261
+ }, error);
262
+ }
263
+ }
264
+ return {
265
+ schema,
266
+ sessionAddress: built.sessionAddress,
267
+ createSessionIx: built.instruction,
268
+ createSessionAccountIx,
269
+ topupDelegateIx,
270
+ };
101
271
  }
102
272
  async createSessionWithCompat(params, send) {
103
- const minimalIx = await this.createSessionIx(params);
104
- return { signature: await send(minimalIx, 'minimal'), schema: 'minimal' };
273
+ const attempts = this.createSessionSchemas(params.schemaPreference);
274
+ let lastError = null;
275
+ for (const schema of attempts) {
276
+ try {
277
+ const built = await this.buildCreateSessionCore(params, schema);
278
+ return { signature: await send(built.instruction, schema), schema };
279
+ }
280
+ catch (error) {
281
+ lastError = error;
282
+ }
283
+ }
284
+ throw this.buildError('All create_session schema attempts failed', {
285
+ operation: 'create_session',
286
+ managerScriptAccount: this.managerScriptAccount,
287
+ vmProgramId: this.vmProgramId,
288
+ authority: params.authority,
289
+ delegate: params.delegate,
290
+ targetProgram: params.targetProgram,
291
+ rpcLabel: params.rpcLabel,
292
+ }, lastError);
105
293
  }
106
294
  async revokeSessionIx(params) {
107
295
  const session = await this.deriveSessionAddress(params.authority, params.delegate, params.targetProgram);
108
- const program = FiveProgram.fromABI(this.managerScriptAccount, SESSION_MANAGER_ABI_MINIMAL, {
109
- fiveVMProgramId: this.vmProgramId,
110
- });
111
- const builder = program
112
- .function('revoke_session')
113
- .accounts({ session, authority: params.authority });
114
- builder.payer(params.payer || params.authority);
115
- const encoded = await builder.instruction();
116
- return new TransactionInstruction({
117
- programId: new PublicKey(encoded.programId),
118
- keys: encoded.keys.map((k) => ({
119
- pubkey: new PublicKey(k.pubkey),
120
- isSigner: k.isSigner,
121
- isWritable: k.isWritable,
122
- })),
123
- data: Buffer.from(encoded.data, 'base64'),
124
- });
296
+ try {
297
+ const program = FiveProgram.fromABI(this.managerScriptAccount, SESSION_MANAGER_ABI_MINIMAL, {
298
+ fiveVMProgramId: this.vmProgramId,
299
+ });
300
+ const builder = program
301
+ .function('revoke_session')
302
+ .accounts({ session, authority: params.authority });
303
+ builder.payer(params.payer || params.authority);
304
+ const encoded = await builder.instruction();
305
+ return new TransactionInstruction({
306
+ programId: new PublicKey(encoded.programId),
307
+ keys: encoded.keys.map((k) => ({
308
+ pubkey: new PublicKey(k.pubkey),
309
+ isSigner: k.isSigner,
310
+ isWritable: k.isWritable,
311
+ })),
312
+ data: Buffer.from(encoded.data, 'base64'),
313
+ });
314
+ }
315
+ catch (error) {
316
+ throw this.buildError('Failed to build revoke_session instruction', {
317
+ operation: 'revoke_session',
318
+ managerScriptAccount: this.managerScriptAccount,
319
+ vmProgramId: this.vmProgramId,
320
+ sessionAddress: session,
321
+ authority: params.authority,
322
+ delegate: params.delegate,
323
+ targetProgram: params.targetProgram,
324
+ rpcLabel: params.rpcLabel,
325
+ }, error);
326
+ }
125
327
  }
126
328
  async prepareSessionAccountTx(input) {
127
329
  const sessionSpace = input.sessionSpace ?? 256;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@5ive-tech/sdk",
3
- "version": "1.1.21",
3
+ "version": "1.1.22",
4
4
  "description": "Client-agnostic TypeScript SDK for Five VM scripts on Solana",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",