@fogo/sessions-sdk 0.0.25 → 0.0.29

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/esm/index.js CHANGED
@@ -5,7 +5,7 @@ import { publicKey as metaplexPublicKey } from "@metaplex-foundation/umi";
5
5
  import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
6
6
  import { sha256 } from "@noble/hashes/sha2";
7
7
  import { fromLegacyPublicKey } from "@solana/compat";
8
- import { generateKeyPair, getAddressFromPublicKey, getProgramDerivedAddress, signatureBytes, verifySignature, } from "@solana/kit";
8
+ import { generateKeyPair, getAddressFromPublicKey, getProgramDerivedAddress, } from "@solana/kit";
9
9
  import { getAssociatedTokenAddressSync, getMint } from "@solana/spl-token";
10
10
  import { ComputeBudgetProgram, Connection, Ed25519Program, Keypair, PublicKey, } from "@solana/web3.js";
11
11
  import { Wormhole, wormhole, routes } from "@wormhole-foundation/sdk";
@@ -43,7 +43,7 @@ export const establishSession = async (options) => {
43
43
  : await generateKeyPair();
44
44
  if (options.unlimited) {
45
45
  return sendSessionEstablishTransaction(options, sessionKey, await Promise.all([
46
- buildIntentInstruction(options, sessionKey),
46
+ buildStartSessionIntentInstruction(options, sessionKey),
47
47
  buildStartSessionInstruction(options, sessionKey),
48
48
  ]), options.sessionEstablishmentLookupTable);
49
49
  }
@@ -53,7 +53,7 @@ export const establishSession = async (options) => {
53
53
  ? await getTokenInfo(options.context, filteredLimits)
54
54
  : [];
55
55
  const [intentInstruction, startSessionInstruction] = await Promise.all([
56
- buildIntentInstruction(options, sessionKey, tokenInfo),
56
+ buildStartSessionIntentInstruction(options, sessionKey, tokenInfo),
57
57
  buildStartSessionInstruction(options, sessionKey, tokenInfo),
58
58
  ]);
59
59
  return sendSessionEstablishTransaction(options, sessionKey, [intentInstruction, startSessionInstruction], options.sessionEstablishmentLookupTable);
@@ -119,6 +119,47 @@ const createSession = async (context, walletPublicKey, sessionKey) => {
119
119
  sessionInfo,
120
120
  };
121
121
  };
122
+ const authorizedTokensSchema = z.union([
123
+ z.object({
124
+ Specific: z.object({
125
+ "0": z.array(z.instanceof(PublicKey)),
126
+ }),
127
+ }),
128
+ z.object({ All: z.object({}) }),
129
+ ]);
130
+ const revokedSessionInfoSchema = z.object({
131
+ user: z.instanceof(PublicKey),
132
+ expiration: z.instanceof(BN),
133
+ authorized_tokens_with_mints: authorizedTokensSchema,
134
+ });
135
+ const activeSessionInfoSchema = z.object({
136
+ authorized_programs: z.union([
137
+ z.object({
138
+ Specific: z.object({
139
+ 0: z.array(z.object({
140
+ program_id: z.instanceof(PublicKey),
141
+ signer_pda: z.instanceof(PublicKey),
142
+ })),
143
+ }),
144
+ }),
145
+ z.object({
146
+ All: z.object({}),
147
+ }),
148
+ ]),
149
+ authorized_tokens: z.union([
150
+ z.object({
151
+ Specific: z.object({
152
+ "0": z.array(z.instanceof(PublicKey)),
153
+ }),
154
+ }),
155
+ z.object({ All: z.object({}) }),
156
+ ]),
157
+ expiration: z.instanceof(BN),
158
+ extra: z.object({
159
+ 0: z.unknown(),
160
+ }),
161
+ user: z.instanceof(PublicKey),
162
+ });
122
163
  const sessionInfoSchema = z
123
164
  .object({
124
165
  session_info: z.union([
@@ -191,37 +232,31 @@ const sessionInfoSchema = z
191
232
  V3: z.object({
192
233
  "0": z.union([
193
234
  z.object({
194
- Revoked: z.instanceof(BN),
235
+ Revoked: z.object({
236
+ "0": revokedSessionInfoSchema,
237
+ }),
238
+ }),
239
+ z.object({
240
+ Active: z.object({
241
+ "0": activeSessionInfoSchema,
242
+ }),
243
+ }),
244
+ ]),
245
+ }),
246
+ }),
247
+ z.object({
248
+ V4: z.object({
249
+ "0": z.union([
250
+ z.object({
251
+ Revoked: z.object({
252
+ "0": revokedSessionInfoSchema,
253
+ }),
195
254
  }),
196
255
  z.object({
197
256
  Active: z.object({
198
257
  "0": z.object({
199
- authorized_programs: z.union([
200
- z.object({
201
- Specific: z.object({
202
- 0: z.array(z.object({
203
- program_id: z.instanceof(PublicKey),
204
- signer_pda: z.instanceof(PublicKey),
205
- })),
206
- }),
207
- }),
208
- z.object({
209
- All: z.object({}),
210
- }),
211
- ]),
212
- authorized_tokens: z.union([
213
- z.object({
214
- Specific: z.object({
215
- "0": z.array(z.instanceof(PublicKey)),
216
- }),
217
- }),
218
- z.object({ All: z.object({}) }),
219
- ]),
220
- expiration: z.instanceof(BN),
221
- extra: z.object({
222
- 0: z.unknown(),
223
- }),
224
- user: z.instanceof(PublicKey),
258
+ domain_hash: z.array(z.number()).length(32),
259
+ active_session_info: activeSessionInfoSchema,
225
260
  }),
226
261
  }),
227
262
  }),
@@ -247,6 +282,10 @@ const sessionInfoSchema = z
247
282
  activeSessionInfo = session_info.V3["0"].Active["0"];
248
283
  minor = 3;
249
284
  }
285
+ else if ("V4" in session_info && "Active" in session_info.V4["0"]) {
286
+ activeSessionInfo = session_info.V4["0"].Active["0"].active_session_info;
287
+ minor = 4;
288
+ }
250
289
  else {
251
290
  return;
252
291
  }
@@ -320,64 +359,23 @@ const getTokenInfo = async (context, limits) => {
320
359
  };
321
360
  }));
322
361
  };
323
- const serializeU16LE = (value) => {
324
- const result = new ArrayBuffer(2);
325
- new DataView(result).setUint16(0, value, true); // littleEndian = true
326
- return new Uint8Array(result);
327
- };
328
- // Some wallets add a prefix to the messag before signing, for example Ledger through Phantom
329
- const addOffchainMessagePrefixToMessageIfNeeded = async (walletPublicKey, signature, message) => {
330
- const publicKey = await crypto.subtle.importKey("raw", walletPublicKey.toBytes(), { name: "Ed25519" }, true, ["verify"]);
331
- if (await verifySignature(publicKey, signature, message)) {
332
- return message;
333
- }
334
- else {
335
- // Source: https://github.com/anza-xyz/solana-sdk/blob/master/offchain-message/src/lib.rs#L162
336
- const messageWithOffchainMessagePrefix = Uint8Array.from([
337
- // eslint-disable-next-line unicorn/number-literal-case
338
- 0xff,
339
- ...new TextEncoder().encode("solana offchain"),
340
- 0,
341
- 1,
342
- ...serializeU16LE(message.length),
343
- ...message,
344
- ]);
345
- if (await verifySignature(publicKey, signature, messageWithOffchainMessagePrefix)) {
346
- return messageWithOffchainMessagePrefix;
347
- }
348
- else {
349
- throw new Error("The signature provided by the browser wallet is not valid");
350
- }
351
- }
352
- };
353
- const buildIntentInstruction = async (options, sessionKey, tokens) => {
354
- const message = await buildMessage({
355
- chainId: options.context.chainId,
356
- domain: options.context.domain,
357
- sessionKey,
358
- expires: options.expires,
359
- tokens,
360
- extra: options.extra,
361
- });
362
- const intentSignature = signatureBytes(await options.signMessage(message));
362
+ const buildStartSessionIntentInstruction = async (options, sessionKey, tokens) => buildIntentInstruction(options, MESSAGE_HEADER, {
363
+ version: `${CURRENT_MAJOR}.${CURRENT_MINOR}`,
364
+ chain_id: options.context.chainId,
365
+ domain: options.context.domain,
366
+ expires: options.expires.toISOString(),
367
+ session_key: await getAddressFromPublicKey(sessionKey.publicKey),
368
+ tokens: serializeTokenList(tokens),
369
+ });
370
+ const buildIntentInstruction = async (options, header, body, extra) => {
371
+ const message = new TextEncoder().encode([header, serializeKV(body), extra && serializeExtra(extra)].join("\n"));
372
+ const { signature, signedMessage } = await options.signMessage(message);
363
373
  return Ed25519Program.createInstructionWithPublicKey({
364
374
  publicKey: options.walletPublicKey.toBytes(),
365
- signature: intentSignature,
366
- message: await addOffchainMessagePrefixToMessageIfNeeded(options.walletPublicKey, intentSignature, message),
375
+ signature,
376
+ message: signedMessage,
367
377
  });
368
378
  };
369
- const buildMessage = async (body) => new TextEncoder().encode([
370
- MESSAGE_HEADER,
371
- serializeKV({
372
- version: `${CURRENT_MAJOR}.${CURRENT_MINOR}`,
373
- chain_id: body.chainId,
374
- domain: body.domain,
375
- expires: body.expires.toISOString(),
376
- session_key: await getAddressFromPublicKey(body.sessionKey.publicKey),
377
- tokens: serializeTokenList(body.tokens),
378
- }),
379
- body.extra && serializeExtra(body.extra),
380
- ].join("\n"));
381
379
  const serializeExtra = (extra) => {
382
380
  for (const [key, value] of Object.entries(extra)) {
383
381
  if (!/^[a-z]+(_[a-z0-9]+)*$/.test(key)) {
@@ -560,24 +558,15 @@ const buildTransferIntentInstruction = async (program, options, symbol, feeToken
560
558
  getNonce(program, options.walletPublicKey, NonceType.Transfer),
561
559
  getMint(options.context.connection, options.mint),
562
560
  ]);
563
- const message = new TextEncoder().encode([
564
- TRANSFER_MESSAGE_HEADER,
565
- serializeKV({
566
- version: `${CURRENT_INTENT_TRANSFER_MAJOR}.${CURRENT_INTENT_TRANSFER_MINOR}`,
567
- chain_id: options.context.chainId,
568
- token: symbol ?? options.mint.toBase58(),
569
- amount: amountToString(options.amount, decimals),
570
- recipient: options.recipient.toBase58(),
571
- fee_token: feeToken,
572
- fee_amount: feeAmount,
573
- nonce: nonce === null ? "1" : nonce.nonce.add(new BN(1)).toString(),
574
- }),
575
- ].join("\n"));
576
- const intentSignature = signatureBytes(await options.signMessage(message));
577
- return Ed25519Program.createInstructionWithPublicKey({
578
- publicKey: options.walletPublicKey.toBytes(),
579
- signature: intentSignature,
580
- message: await addOffchainMessagePrefixToMessageIfNeeded(options.walletPublicKey, intentSignature, message),
561
+ return buildIntentInstruction(options, TRANSFER_MESSAGE_HEADER, {
562
+ version: `${CURRENT_INTENT_TRANSFER_MAJOR}.${CURRENT_INTENT_TRANSFER_MINOR}`,
563
+ chain_id: options.context.chainId,
564
+ token: symbol ?? options.mint.toBase58(),
565
+ amount: amountToString(options.amount, decimals),
566
+ recipient: options.recipient.toBase58(),
567
+ fee_token: feeToken,
568
+ fee_amount: feeAmount,
569
+ nonce: nonce === null ? "1" : nonce.nonce.add(new BN(1)).toString(),
581
570
  });
582
571
  };
583
572
  const BRIDGE_OUT_MESSAGE_HEADER = `Fogo Bridge Transfer:
@@ -679,25 +668,16 @@ const getNttPdas = async (options, wh, program, outboxItemPublicKey, quotePayeeA
679
668
  };
680
669
  const buildBridgeOutIntent = async (program, options, decimals, symbol, feeToken, feeAmount) => {
681
670
  const nonce = await getNonce(program, options.walletPublicKey, NonceType.Bridge);
682
- const message = new TextEncoder().encode([
683
- BRIDGE_OUT_MESSAGE_HEADER,
684
- serializeKV({
685
- version: `${CURRENT_BRIDGE_OUT_MAJOR}.${CURRENT_BRIDGE_OUT_MINOR}`,
686
- from_chain_id: options.context.chainId,
687
- to_chain_id: "solana",
688
- token: symbol ?? options.fromToken.mint.toBase58(),
689
- amount: amountToString(options.amount, decimals),
690
- recipient_address: options.walletPublicKey.toBase58(),
691
- fee_token: feeToken,
692
- fee_amount: feeAmount,
693
- nonce: nonce === null ? "1" : nonce.nonce.add(new BN(1)).toString(),
694
- }),
695
- ].join("\n"));
696
- const intentSignature = signatureBytes(await options.solanaWallet.signMessage(message));
697
- return Ed25519Program.createInstructionWithPublicKey({
698
- publicKey: options.walletPublicKey.toBytes(),
699
- signature: intentSignature,
700
- message: await addOffchainMessagePrefixToMessageIfNeeded(options.walletPublicKey, intentSignature, message),
671
+ return buildIntentInstruction(options, BRIDGE_OUT_MESSAGE_HEADER, {
672
+ version: `${CURRENT_BRIDGE_OUT_MAJOR}.${CURRENT_BRIDGE_OUT_MINOR}`,
673
+ from_chain_id: options.context.chainId,
674
+ to_chain_id: "solana",
675
+ token: symbol ?? options.fromToken.mint.toBase58(),
676
+ amount: amountToString(options.amount, decimals),
677
+ recipient_address: options.walletPublicKey.toBase58(),
678
+ fee_token: feeToken,
679
+ fee_amount: feeAmount,
680
+ nonce: nonce === null ? "1" : nonce.nonce.add(new BN(1)).toString(),
701
681
  });
702
682
  };
703
683
  export const bridgeIn = async (options) => {
@@ -711,10 +691,9 @@ export const bridgeIn = async (options) => {
711
691
  address: () => options.walletPublicKey.toBase58(),
712
692
  chain: () => "Solana",
713
693
  sign: (transactions) => Promise.all(transactions.map(async ({ transaction }) => {
714
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
715
- const signedTx = await options.solanaWallet.signTransaction(
694
+ const signedTx = await options.signTransaction(
716
695
  // Hooray for Wormhole's incomplete typing eh?
717
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
696
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
718
697
  transaction.transaction);
719
698
  // Hooray for Wormhole's incomplete typing eh?
720
699
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@fogo/sessions-sdk",
3
- "version": "0.0.25",
3
+ "version": "0.0.29",
4
4
  "description": "A set of utilities for integrating with Fogo sessions",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/fogo-foundation/fogo-sessions",
8
+ "directory": "packages/sessions-sdk-ts"
9
+ },
5
10
  "keywords": [
6
11
  "fogo",
7
12
  "sessions",
@@ -43,7 +48,7 @@
43
48
  "@wormhole-foundation/sdk-solana-ntt": "^4.0.1",
44
49
  "bn.js": "^5.1.2",
45
50
  "bs58": "^6.0.0",
46
- "zod": "^3.25.62",
47
- "@fogo/sessions-idls": "^0.0.11"
51
+ "zod": "3.25.67",
52
+ "@fogo/sessions-idls": "^0.0.12"
48
53
  }
49
54
  }