@pooflabs/web 0.0.38 → 0.0.39

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.
@@ -12445,6 +12445,13 @@ async function signTransaction(transaction) {
12445
12445
  }
12446
12446
  return config.authProvider.signTransaction(transaction);
12447
12447
  }
12448
+ async function signAndSubmitTransaction(transaction, feePayer) {
12449
+ const config = await getConfig();
12450
+ if (!config.authProvider) {
12451
+ throw new Error('Auth provider not initialized. Please call init() first.');
12452
+ }
12453
+ return config.authProvider.signAndSubmitTransaction(transaction, feePayer);
12454
+ }
12448
12455
 
12449
12456
  const activeConnections = {};
12450
12457
  const responseCache = {};
@@ -12666,7 +12673,7 @@ async function loadDependencies() {
12666
12673
  const [reactModule, reactDomModule, phantomModule] = await Promise.all([
12667
12674
  import('react'),
12668
12675
  import('react-dom/client'),
12669
- Promise.resolve().then(function () { return require('./index-C6HaRwOE.js'); })
12676
+ Promise.resolve().then(function () { return require('./index-C-_15_Cq.js'); })
12670
12677
  ]);
12671
12678
  React$1 = reactModule;
12672
12679
  ReactDOM$1 = reactDomModule;
@@ -13112,18 +13119,15 @@ class PhantomWalletProvider {
13112
13119
  await this.ensureSolanaReady();
13113
13120
  }
13114
13121
  catch (error) {
13115
- // Reconnection failed - log user out and throw
13116
13122
  console.error('Solana provider reconnection failed, logging out:', error.message);
13117
13123
  await this.logout();
13118
13124
  throw new Error('Wallet connection lost. Please reconnect.');
13119
13125
  }
13120
- // Ensure connected
13121
13126
  if (!((_a = this.phantomMethods) === null || _a === void 0 ? void 0 : _a.isConnected)) {
13122
13127
  const user = await this.login();
13123
13128
  if (!user) {
13124
13129
  throw new Error('Failed to connect wallet');
13125
13130
  }
13126
- // Wait for solana to be ready after login
13127
13131
  try {
13128
13132
  await this.ensureSolanaReady();
13129
13133
  }
@@ -13136,21 +13140,7 @@ class PhantomWalletProvider {
13136
13140
  if (!((_b = this.phantomMethods) === null || _b === void 0 ? void 0 : _b.solana)) {
13137
13141
  throw new Error('Solana signing not available');
13138
13142
  }
13139
- let rpcUrl = this.networkUrl;
13140
- if (this.networkUrl == null) {
13141
- if (solTransactionData.network === 'solana_devnet') {
13142
- rpcUrl = SOLANA_DEVNET_RPC_URL;
13143
- }
13144
- else if (solTransactionData.network === 'solana_mainnet') {
13145
- rpcUrl = SOLANA_MAINNET_RPC_URL;
13146
- }
13147
- else if (solTransactionData.network === 'surfnet') {
13148
- rpcUrl = SURFNET_RPC_URL;
13149
- }
13150
- else {
13151
- throw new Error('Invalid network for Phantom wallet');
13152
- }
13153
- }
13143
+ const rpcUrl = this.getRpcUrl(solTransactionData.network);
13154
13144
  const connection = new web3_js.Connection(rpcUrl, 'confirmed');
13155
13145
  try {
13156
13146
  const remainingAccounts = convertRemainingAccounts(solTransactionData.txArgs[0].remainingAccounts);
@@ -13190,7 +13180,7 @@ class PhantomWalletProvider {
13190
13180
  finalDeduped.push(acc);
13191
13181
  }
13192
13182
  }
13193
- const { tx, blockhash, lastValidBlockHeight } = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, publicKey, {
13183
+ const { tx } = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, publicKey, {
13194
13184
  app_id,
13195
13185
  documents: solTransactionData.txArgs[0].setDocumentData,
13196
13186
  delete_paths: solTransactionData.txArgs[0].deletePaths,
@@ -13205,19 +13195,8 @@ class PhantomWalletProvider {
13205
13195
  data: ""
13206
13196
  };
13207
13197
  }
13208
- const signature = await connection.sendRawTransaction(signedTx.serialize());
13209
- const confirmation = await connection.confirmTransaction({
13210
- signature,
13211
- blockhash,
13212
- lastValidBlockHeight,
13213
- }, 'confirmed');
13214
- if (confirmation.value.err) {
13215
- throw new Error(`Transaction failed: ${confirmation.value.err.toString()}`);
13216
- }
13217
- const txInfo = await connection.getParsedTransaction(signature, {
13218
- maxSupportedTransactionVersion: 0,
13219
- commitment: 'confirmed'
13220
- });
13198
+ // Submit using shared helper
13199
+ const { signature, txInfo } = await this.submitSignedTransaction(signedTx, connection);
13221
13200
  return {
13222
13201
  transactionSignature: signature,
13223
13202
  blockNumber: (txInfo === null || txInfo === void 0 ? void 0 : txInfo.slot) || 0,
@@ -13243,6 +13222,16 @@ class PhantomWalletProvider {
13243
13222
  throw new Error(`Failed to execute transaction: ${error.message}`);
13244
13223
  }
13245
13224
  }
13225
+ /**
13226
+ * Signs a Solana transaction without submitting it.
13227
+ *
13228
+ * This method handles blockhash automatically if not set - you do NOT need to
13229
+ * set recentBlockhash on the transaction before calling this method.
13230
+ * The network/RPC URL is derived from the provider's configuration (set during initialization).
13231
+ *
13232
+ * @param transaction - The transaction to sign (Transaction or VersionedTransaction)
13233
+ * @returns The signed transaction
13234
+ */
13246
13235
  async signTransaction(transaction) {
13247
13236
  var _a, _b, _c, _d;
13248
13237
  try {
@@ -13271,6 +13260,36 @@ class PhantomWalletProvider {
13271
13260
  if (!((_b = this.phantomMethods) === null || _b === void 0 ? void 0 : _b.solana)) {
13272
13261
  throw new Error('Solana signing not available');
13273
13262
  }
13263
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
13264
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
13265
+ // Ensure blockhash is set before signing
13266
+ if (isLegacyTransaction) {
13267
+ const legacyTx = transaction;
13268
+ if (!legacyTx.recentBlockhash) {
13269
+ const rpcUrl = this.getRpcUrl();
13270
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
13271
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
13272
+ legacyTx.recentBlockhash = blockhash;
13273
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
13274
+ }
13275
+ // Set feePayer if not already set
13276
+ if (!legacyTx.feePayer) {
13277
+ const solAddress = this.phantomMethods.addresses.find((addr) => addr.addressType === phantomReactSdk.AddressType.solana);
13278
+ if (solAddress) {
13279
+ legacyTx.feePayer = new web3_js.PublicKey(solAddress.address);
13280
+ }
13281
+ }
13282
+ }
13283
+ else {
13284
+ // VersionedTransaction
13285
+ const versionedTx = transaction;
13286
+ if (!versionedTx.message.recentBlockhash) {
13287
+ const rpcUrl = this.getRpcUrl();
13288
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
13289
+ const { blockhash } = await connection.getLatestBlockhash('confirmed');
13290
+ versionedTx.message.recentBlockhash = blockhash;
13291
+ }
13292
+ }
13274
13293
  try {
13275
13294
  return await this.phantomMethods.solana.signTransaction(transaction);
13276
13295
  }
@@ -13284,6 +13303,102 @@ class PhantomWalletProvider {
13284
13303
  throw new Error(`Failed to sign transaction: ${error.message}`);
13285
13304
  }
13286
13305
  }
13306
+ /**
13307
+ * Signs and submits a Solana transaction to the network.
13308
+ *
13309
+ * This method handles blockhash and transaction confirmation automatically - you do NOT need to
13310
+ * set recentBlockhash or lastValidBlockHeight on the transaction before calling this method.
13311
+ * The network/RPC URL is derived from the provider's configuration (set during initialization).
13312
+ *
13313
+ * @param transaction - The transaction to sign and submit (Transaction or VersionedTransaction)
13314
+ * @param feePayer - Optional fee payer public key. If not provided and the transaction doesn't
13315
+ * already have a feePayer set, the connected wallet address will be used.
13316
+ * Useful for co-signing scenarios where a different account pays the fees.
13317
+ * @returns The transaction signature
13318
+ */
13319
+ async signAndSubmitTransaction(transaction, feePayer) {
13320
+ var _a, _b, _c, _d, _e, _f, _g, _h;
13321
+ try {
13322
+ await this.ensureSolanaReady();
13323
+ }
13324
+ catch (error) {
13325
+ console.error('Solana provider reconnection failed, logging out:', error.message);
13326
+ await this.logout();
13327
+ throw new Error('Wallet connection lost. Please reconnect.');
13328
+ }
13329
+ if (!((_a = this.phantomMethods) === null || _a === void 0 ? void 0 : _a.isConnected)) {
13330
+ const user = await this.login();
13331
+ if (!user) {
13332
+ throw new Error('Failed to connect wallet');
13333
+ }
13334
+ try {
13335
+ await this.ensureSolanaReady();
13336
+ }
13337
+ catch (error) {
13338
+ console.error('Solana provider reconnection failed after login, logging out:', error.message);
13339
+ await this.logout();
13340
+ throw new Error('Wallet connection lost. Please reconnect.');
13341
+ }
13342
+ }
13343
+ if (!((_b = this.phantomMethods) === null || _b === void 0 ? void 0 : _b.solana)) {
13344
+ throw new Error('Solana signing not available');
13345
+ }
13346
+ const rpcUrl = this.getRpcUrl();
13347
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
13348
+ try {
13349
+ // Get fresh blockhash and set it on the transaction before signing
13350
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
13351
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
13352
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
13353
+ if (isLegacyTransaction) {
13354
+ const legacyTx = transaction;
13355
+ legacyTx.recentBlockhash = blockhash;
13356
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
13357
+ // Set feePayer if not already set
13358
+ if (!legacyTx.feePayer) {
13359
+ if (feePayer) {
13360
+ legacyTx.feePayer = feePayer;
13361
+ }
13362
+ else {
13363
+ // Use connected wallet address as feePayer
13364
+ const solAddress = this.phantomMethods.addresses.find((addr) => addr.addressType === phantomReactSdk.AddressType.solana);
13365
+ if (solAddress) {
13366
+ legacyTx.feePayer = new web3_js.PublicKey(solAddress.address);
13367
+ }
13368
+ }
13369
+ }
13370
+ }
13371
+ else {
13372
+ // VersionedTransaction
13373
+ const versionedTx = transaction;
13374
+ versionedTx.message.recentBlockhash = blockhash;
13375
+ // Note: VersionedTransaction feePayer is set in the message at creation time
13376
+ // and cannot be modified after creation
13377
+ }
13378
+ // Sign the transaction
13379
+ const signedTx = await this.phantomMethods.solana.signTransaction(transaction);
13380
+ // Submit using shared helper with the blockhash we set
13381
+ const { signature } = await this.submitSignedTransactionWithBlockhash(signedTx, connection, blockhash, lastValidBlockHeight);
13382
+ return signature;
13383
+ }
13384
+ catch (error) {
13385
+ // Check if this is a connection error - if so, log out
13386
+ if (((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.includes('not connected')) || ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.includes('connect first'))) {
13387
+ console.error('Solana provider connection lost during transaction, logging out');
13388
+ await this.logout();
13389
+ throw new Error('Wallet connection lost. Please reconnect.');
13390
+ }
13391
+ const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
13392
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user rejected')) ||
13393
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user denied')) ||
13394
+ ((_g = error === null || error === void 0 ? void 0 : error.message) === null || _g === void 0 ? void 0 : _g.toLowerCase().includes('user cancelled')) ||
13395
+ ((_h = error === null || error === void 0 ? void 0 : error.message) === null || _h === void 0 ? void 0 : _h.toLowerCase().includes('user canceled'));
13396
+ if (!isUserRejection) {
13397
+ console.error('Failed to execute transaction', error);
13398
+ }
13399
+ throw new Error(`Failed to execute transaction: ${error.message}`);
13400
+ }
13401
+ }
13287
13402
  async signMessage(message) {
13288
13403
  var _a, _b, _c, _d, _e, _f, _g, _h;
13289
13404
  try {
@@ -13354,6 +13469,50 @@ class PhantomWalletProvider {
13354
13469
  await this.ensureReady();
13355
13470
  return this.phantomMethods;
13356
13471
  }
13472
+ /* ----------------------------------------------------------- *
13473
+ * Private Helpers
13474
+ * ----------------------------------------------------------- */
13475
+ getRpcUrl(network) {
13476
+ if (this.networkUrl) {
13477
+ return this.networkUrl;
13478
+ }
13479
+ if (network === 'solana_devnet') {
13480
+ return SOLANA_DEVNET_RPC_URL;
13481
+ }
13482
+ else if (network === 'solana_mainnet') {
13483
+ return SOLANA_MAINNET_RPC_URL;
13484
+ }
13485
+ else if (network === 'surfnet') {
13486
+ return SURFNET_RPC_URL;
13487
+ }
13488
+ return SOLANA_MAINNET_RPC_URL; // default to mainnet
13489
+ }
13490
+ async submitSignedTransaction(signedTx, connection) {
13491
+ // Get fresh blockhash for confirmation
13492
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
13493
+ return this.submitSignedTransactionWithBlockhash(signedTx, connection, blockhash, lastValidBlockHeight);
13494
+ }
13495
+ async submitSignedTransactionWithBlockhash(signedTx, connection, blockhash, lastValidBlockHeight) {
13496
+ // Submit the transaction
13497
+ const signature = await connection.sendRawTransaction(signedTx.serialize(), {
13498
+ preflightCommitment: 'confirmed'
13499
+ });
13500
+ // Confirm using blockhash strategy (same as runTransaction)
13501
+ const confirmation = await connection.confirmTransaction({
13502
+ signature,
13503
+ blockhash,
13504
+ lastValidBlockHeight,
13505
+ }, 'confirmed');
13506
+ if (confirmation.value.err) {
13507
+ throw new Error(`Transaction failed: ${confirmation.value.err.toString()}`);
13508
+ }
13509
+ // Get transaction info
13510
+ const txInfo = await connection.getParsedTransaction(signature, {
13511
+ maxSupportedTransactionVersion: 0,
13512
+ commitment: 'confirmed'
13513
+ });
13514
+ return { signature, txInfo };
13515
+ }
13357
13516
  }
13358
13517
  PhantomWalletProvider.instance = null;
13359
13518
 
@@ -31865,6 +32024,8 @@ class PrivyWalletProvider {
31865
32024
  this.pendingSignTransaction = null;
31866
32025
  // This is used to store pending signMessage calls until the wallet is connected
31867
32026
  this.pendingSignMessage = null;
32027
+ // This is used to store pending signAndSubmitTransaction calls until the wallet is connected
32028
+ this.pendingSignAndSubmitTransaction = null;
31868
32029
  this.networkUrl = networkUrl;
31869
32030
  if (typeof window === 'undefined') {
31870
32031
  throw new Error('PrivyWalletProvider can only be instantiated in a browser environment');
@@ -31981,6 +32142,18 @@ class PrivyWalletProvider {
31981
32142
  }
31982
32143
  that.pendingSignMessage = null;
31983
32144
  }
32145
+ // If there's a pending signAndSubmitTransaction, execute it now
32146
+ if (that.pendingSignAndSubmitTransaction) {
32147
+ const { transaction, feePayer, resolve, reject } = that.pendingSignAndSubmitTransaction;
32148
+ try {
32149
+ const result = await that.signAndSubmitTransaction(transaction, feePayer);
32150
+ resolve(result);
32151
+ }
32152
+ catch (error) {
32153
+ reject(error);
32154
+ }
32155
+ that.pendingSignAndSubmitTransaction = null;
32156
+ }
31984
32157
  },
31985
32158
  onError: (error) => {
31986
32159
  // Only log errors that aren't user-initiated cancellations
@@ -31999,6 +32172,10 @@ class PrivyWalletProvider {
31999
32172
  that.pendingSignMessage.reject(error);
32000
32173
  that.pendingSignMessage = null;
32001
32174
  }
32175
+ if (that.pendingSignAndSubmitTransaction) {
32176
+ that.pendingSignAndSubmitTransaction.reject(error);
32177
+ that.pendingSignAndSubmitTransaction = null;
32178
+ }
32002
32179
  }
32003
32180
  });
32004
32181
  const { login } = privyImports.useLogin({
@@ -32145,7 +32322,7 @@ class PrivyWalletProvider {
32145
32322
  await this.privyMethods.logout();
32146
32323
  }
32147
32324
  async runTransaction(_evmTransactionData, solTransactionData, options) {
32148
- var _a, _b, _c, _d;
32325
+ var _a;
32149
32326
  await this.ensureReady();
32150
32327
  let session = await WebSessionManager.getSession();
32151
32328
  let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
@@ -32180,21 +32357,7 @@ class PrivyWalletProvider {
32180
32357
  if (solTransactionData == null) {
32181
32358
  throw new Error("Solana transaction data is required");
32182
32359
  }
32183
- let rpcUrl = this.networkUrl;
32184
- if (this.networkUrl == null) {
32185
- if (solTransactionData.network === 'solana_devnet') {
32186
- rpcUrl = SOLANA_DEVNET_RPC_URL;
32187
- }
32188
- else if (solTransactionData.network === 'solana_mainnet') {
32189
- rpcUrl = SOLANA_MAINNET_RPC_URL;
32190
- }
32191
- else if (solTransactionData.network === 'surfnet') {
32192
- rpcUrl = SURFNET_RPC_URL$1;
32193
- }
32194
- else {
32195
- throw new Error('Invalid network for Phantom wallet');
32196
- }
32197
- }
32360
+ const rpcUrl = this.getRpcUrl(solTransactionData.network);
32198
32361
  const connection = new web3_js.Connection(rpcUrl, "confirmed");
32199
32362
  const remainingAccounts = convertRemainingAccounts(solTransactionData.txArgs[0].remainingAccounts);
32200
32363
  let app_id = solTransactionData.appId;
@@ -32220,71 +32383,28 @@ class PrivyWalletProvider {
32220
32383
  }
32221
32384
  }
32222
32385
  const { tx, blockhash, lastValidBlockHeight } = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, new web3_js.PublicKey(wallet.address), { app_id, documents: solTransactionData.txArgs[0].setDocumentData, delete_paths: solTransactionData.txArgs[0].deletePaths, txData: solTransactionData.txArgs[0].txData }, finalDeduped, solTransactionData.lutKey, solTransactionData.preInstructions, false);
32223
- if (tx instanceof web3_js.Transaction) {
32386
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
32387
+ const isLegacyTx = 'recentBlockhash' in tx && !('message' in tx && 'staticAccountKeys' in tx.message);
32388
+ if (isLegacyTx) {
32224
32389
  tx.recentBlockhash = blockhash;
32225
32390
  tx.lastValidBlockHeight = lastValidBlockHeight;
32226
32391
  }
32227
- else if (tx instanceof web3_js.VersionedTransaction) {
32392
+ else {
32228
32393
  tx.message.recentBlockhash = blockhash;
32229
32394
  }
32230
32395
  try {
32231
32396
  if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
32232
- // v3 API: serialize transaction and pass wallet/chain
32233
- let serializedTx;
32234
- if (tx instanceof web3_js.Transaction) {
32235
- serializedTx = tx.serialize({ requireAllSignatures: false, verifySignatures: false });
32236
- }
32237
- else {
32238
- serializedTx = tx.serialize();
32239
- }
32240
- const signedTx = await ((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.signTransaction({
32241
- transaction: serializedTx,
32242
- wallet: privyWallet,
32243
- chain: this.chainId
32244
- }));
32397
+ // Just sign, don't submit - return raw signed bytes (same as original runTransaction)
32398
+ const signedTx = await this.signTransactionRaw(tx, privyWallet);
32245
32399
  return {
32246
- signedTransaction: signedTx,
32400
+ signedTransaction: signedTx, // Raw Uint8Array from Privy
32247
32401
  blockNumber: 0,
32248
32402
  gasUsed: "0",
32249
32403
  data: ""
32250
32404
  };
32251
32405
  }
32252
- const isSurfnet = connection.rpcEndpoint === SURFNET_RPC_URL$1;
32253
- let txSignature;
32254
- if (isSurfnet) {
32255
- // v3 API: serialize transaction and pass wallet/chain
32256
- let serializedForSign;
32257
- if (tx instanceof web3_js.Transaction) {
32258
- serializedForSign = tx.serialize({ requireAllSignatures: false, verifySignatures: false });
32259
- }
32260
- else {
32261
- serializedForSign = tx.serialize();
32262
- }
32263
- const signedTx = await ((_c = this.privyMethods) === null || _c === void 0 ? void 0 : _c.signTransaction({
32264
- transaction: serializedForSign,
32265
- wallet: privyWallet,
32266
- chain: this.chainId
32267
- }));
32268
- txSignature = await connection.sendRawTransaction(signedTx);
32269
- }
32270
- else {
32271
- // v3 API: transaction must be Uint8Array, pass wallet object
32272
- // Serialize without requiring signatures - Privy will sign it
32273
- let serializedTx;
32274
- if (tx instanceof web3_js.Transaction) {
32275
- serializedTx = tx.serialize({ requireAllSignatures: false, verifySignatures: false });
32276
- }
32277
- else {
32278
- // VersionedTransaction
32279
- serializedTx = tx.serialize();
32280
- }
32281
- const result = await ((_d = this.privyMethods) === null || _d === void 0 ? void 0 : _d.useSendTransactionSolana.signAndSendTransaction({
32282
- transaction: serializedTx,
32283
- wallet: privyWallet,
32284
- chain: this.chainId
32285
- }));
32286
- txSignature = result.signature;
32287
- }
32406
+ // Sign and submit using shared helper
32407
+ const txSignature = await this.signAndSubmitInternal(tx, privyWallet, rpcUrl);
32288
32408
  return {
32289
32409
  transactionSignature: txSignature,
32290
32410
  blockNumber: 0,
@@ -32297,58 +32417,262 @@ class PrivyWalletProvider {
32297
32417
  throw err;
32298
32418
  }
32299
32419
  }
32420
+ /**
32421
+ * Signs a Solana transaction without submitting it.
32422
+ *
32423
+ * This method handles blockhash automatically if not set - you do NOT need to
32424
+ * set recentBlockhash on the transaction before calling this method.
32425
+ * The network/RPC URL is derived from the provider's configuration (set during initialization).
32426
+ *
32427
+ * @param transaction - The transaction to sign (Transaction or VersionedTransaction)
32428
+ * @returns The signed transaction
32429
+ */
32300
32430
  async signTransaction(transaction) {
32301
- var _a, _b;
32431
+ var _a;
32432
+ await this.ensureReady();
32433
+ let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
32434
+ let session = await WebSessionManager.getSession();
32435
+ let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
32436
+ let privyWallet = privyWallets === null || privyWallets === void 0 ? void 0 : privyWallets.find((wallet) => wallet.address === sessionAddress);
32437
+ // If there's already a pending sign transaction, throw an error to prevent overlapping calls
32438
+ if (this.pendingSignTransaction) {
32439
+ throw new Error("Oops... something went wrong. Please try again.");
32440
+ }
32441
+ // If wallet not connected, trigger connection and queue the signing
32442
+ if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
32443
+ return new Promise((resolve, reject) => {
32444
+ this.pendingSignTransaction = {
32445
+ resolve,
32446
+ reject,
32447
+ transaction
32448
+ };
32449
+ this.privyMethods.connectWallet();
32450
+ // Set a timeout to reject the promise if connection takes too long
32451
+ setTimeout(() => {
32452
+ if (this.pendingSignTransaction) {
32453
+ this.pendingSignTransaction.reject(new Error("Wallet connection timed out"));
32454
+ this.pendingSignTransaction = null;
32455
+ }
32456
+ }, 30000); // 30 seconds timeout
32457
+ });
32458
+ }
32459
+ // Privy requires serialized transaction bytes, which requires a blockhash.
32460
+ // If the transaction doesn't have one, get a fresh blockhash and set it.
32461
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
32462
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
32463
+ if (isLegacyTransaction) {
32464
+ const legacyTx = transaction;
32465
+ if (!legacyTx.recentBlockhash) {
32466
+ const rpcUrl = this.getRpcUrl();
32467
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
32468
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
32469
+ legacyTx.recentBlockhash = blockhash;
32470
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
32471
+ }
32472
+ // Set feePayer if not already set
32473
+ if (!legacyTx.feePayer) {
32474
+ legacyTx.feePayer = new web3_js.PublicKey(privyWallet.address);
32475
+ }
32476
+ }
32477
+ else {
32478
+ // VersionedTransaction
32479
+ const versionedTx = transaction;
32480
+ if (!versionedTx.message.recentBlockhash) {
32481
+ const rpcUrl = this.getRpcUrl();
32482
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
32483
+ const { blockhash } = await connection.getLatestBlockhash('confirmed');
32484
+ versionedTx.message.recentBlockhash = blockhash;
32485
+ }
32486
+ }
32487
+ // Sign using raw method, then deserialize for the public API
32488
+ const signedTxRaw = await this.signTransactionRaw(transaction, privyWallet);
32489
+ return this.deserializeSignedTransaction(signedTxRaw);
32490
+ }
32491
+ /**
32492
+ * Signs and submits a Solana transaction to the network.
32493
+ *
32494
+ * This method handles blockhash and transaction confirmation automatically - you do NOT need to
32495
+ * set recentBlockhash or lastValidBlockHeight on the transaction before calling this method.
32496
+ * The network/RPC URL is derived from the provider's configuration (set during initialization).
32497
+ *
32498
+ * @param transaction - The transaction to sign and submit (Transaction or VersionedTransaction)
32499
+ * @param feePayer - Optional fee payer public key. If not provided and the transaction doesn't
32500
+ * already have a feePayer set, the connected wallet address will be used.
32501
+ * Useful for co-signing scenarios where a different account pays the fees.
32502
+ * @returns The transaction signature
32503
+ */
32504
+ async signAndSubmitTransaction(transaction, feePayer) {
32505
+ var _a;
32506
+ await this.ensureReady();
32507
+ let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
32508
+ let session = await WebSessionManager.getSession();
32509
+ let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
32510
+ let privyWallet = privyWallets === null || privyWallets === void 0 ? void 0 : privyWallets.find((wallet) => wallet.address === sessionAddress);
32511
+ // If there's already a pending signAndSubmitTransaction, throw an error to prevent overlapping calls
32512
+ if (this.pendingSignAndSubmitTransaction) {
32513
+ throw new Error("Oops... something went wrong. Please try again.");
32514
+ }
32515
+ // If wallet not connected, trigger connection and queue the signing
32516
+ if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
32517
+ return new Promise((resolve, reject) => {
32518
+ this.pendingSignAndSubmitTransaction = {
32519
+ resolve,
32520
+ reject,
32521
+ transaction,
32522
+ feePayer
32523
+ };
32524
+ this.privyMethods.connectWallet();
32525
+ // Set a timeout to reject the promise if connection takes too long
32526
+ setTimeout(() => {
32527
+ if (this.pendingSignAndSubmitTransaction) {
32528
+ this.pendingSignAndSubmitTransaction.reject(new Error("Wallet connection timed out"));
32529
+ this.pendingSignAndSubmitTransaction = null;
32530
+ }
32531
+ }, 30000); // 30 seconds timeout
32532
+ });
32533
+ }
32534
+ // Get RPC URL and create connection
32535
+ const rpcUrl = this.getRpcUrl();
32536
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
32537
+ // Get fresh blockhash and set it on the transaction before signing
32538
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
32539
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
32540
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
32541
+ if (isLegacyTransaction) {
32542
+ const legacyTx = transaction;
32543
+ legacyTx.recentBlockhash = blockhash;
32544
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
32545
+ // Set feePayer if not already set
32546
+ if (!legacyTx.feePayer) {
32547
+ legacyTx.feePayer = feePayer !== null && feePayer !== void 0 ? feePayer : new web3_js.PublicKey(privyWallet.address);
32548
+ }
32549
+ }
32550
+ else {
32551
+ // VersionedTransaction
32552
+ const versionedTx = transaction;
32553
+ versionedTx.message.recentBlockhash = blockhash;
32554
+ // Note: VersionedTransaction feePayer is set in the message at creation time
32555
+ // and cannot be modified after creation
32556
+ }
32557
+ // Use shared sign and submit logic
32558
+ return this.signAndSubmitInternal(transaction, privyWallet, rpcUrl);
32559
+ }
32560
+ // ============ Private Helpers ============
32561
+ getRpcUrl(network) {
32562
+ if (this.networkUrl) {
32563
+ return this.networkUrl;
32564
+ }
32565
+ if (network === 'solana_devnet') {
32566
+ return SOLANA_DEVNET_RPC_URL;
32567
+ }
32568
+ else if (network === 'solana_mainnet') {
32569
+ return SOLANA_MAINNET_RPC_URL;
32570
+ }
32571
+ else if (network === 'surfnet') {
32572
+ return SURFNET_RPC_URL$1;
32573
+ }
32574
+ return SOLANA_MAINNET_RPC_URL; // default to mainnet
32575
+ }
32576
+ /**
32577
+ * Internal sign transaction - serializes and signs via Privy
32578
+ * Returns the raw result from Privy (Uint8Array)
32579
+ * This mirrors exactly what runTransaction was doing
32580
+ */
32581
+ async signTransactionRaw(transaction, privyWallet) {
32582
+ var _a;
32583
+ // Serialize the transaction
32584
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
32585
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
32586
+ let serializedForSign;
32587
+ if (isLegacyTransaction) {
32588
+ serializedForSign = transaction.serialize({ requireAllSignatures: false, verifySignatures: false });
32589
+ }
32590
+ else {
32591
+ serializedForSign = transaction.serialize();
32592
+ }
32593
+ // Sign via Privy - returns { signedTransaction: Uint8Array }
32594
+ const result = await ((_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.signTransaction({
32595
+ transaction: serializedForSign,
32596
+ wallet: privyWallet,
32597
+ chain: this.chainId
32598
+ }));
32599
+ // Privy returns { signedTransaction: Uint8Array }, unwrap it
32600
+ const signedTx = (result === null || result === void 0 ? void 0 : result.signedTransaction) || result;
32601
+ return signedTx;
32602
+ }
32603
+ /**
32604
+ * Deserialize a signed transaction from Uint8Array to Transaction object
32605
+ */
32606
+ deserializeSignedTransaction(signedTxRaw) {
32607
+ // Handle different formats Privy might return
32608
+ let signedTx;
32609
+ if (signedTxRaw instanceof Uint8Array) {
32610
+ signedTx = signedTxRaw;
32611
+ }
32612
+ else if (Array.isArray(signedTxRaw)) {
32613
+ signedTx = new Uint8Array(signedTxRaw);
32614
+ }
32615
+ else if (signedTxRaw && typeof signedTxRaw === 'object' && 'signedTransaction' in signedTxRaw) {
32616
+ // Privy might wrap the result
32617
+ signedTx = signedTxRaw.signedTransaction instanceof Uint8Array
32618
+ ? signedTxRaw.signedTransaction
32619
+ : new Uint8Array(signedTxRaw.signedTransaction);
32620
+ }
32621
+ else if (Buffer.isBuffer(signedTxRaw)) {
32622
+ signedTx = new Uint8Array(signedTxRaw);
32623
+ }
32624
+ else {
32625
+ throw new Error(`Unexpected signed transaction format: ${typeof signedTxRaw}`);
32626
+ }
32627
+ // Try to deserialize as VersionedTransaction first, fall back to legacy Transaction
32302
32628
  try {
32303
- await this.ensureReady();
32304
- let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
32305
- let session = await WebSessionManager.getSession();
32306
- let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
32307
- let privyWallet = privyWallets === null || privyWallets === void 0 ? void 0 : privyWallets.find((wallet) => wallet.address === sessionAddress);
32308
- // If there's already a pending sign transaction, throw an error to prevent overlapping calls
32309
- if (this.pendingSignTransaction) {
32310
- throw new Error("Oops... something went wrong. Please try again.");
32629
+ return web3_js.VersionedTransaction.deserialize(signedTx);
32630
+ }
32631
+ catch (_a) {
32632
+ return web3_js.Transaction.from(signedTx);
32633
+ }
32634
+ }
32635
+ /**
32636
+ * Internal sign and submit - handles Surfnet vs non-Surfnet logic
32637
+ * This is the core submission logic used by both signAndSubmitTransaction and runTransaction
32638
+ *
32639
+ * For Surfnet: sign with signTransactionRaw, then sendRawTransaction
32640
+ * For non-Surfnet: use Privy's signAndSendTransaction (combined operation)
32641
+ */
32642
+ async signAndSubmitInternal(transaction, privyWallet, rpcUrl) {
32643
+ var _a;
32644
+ const isSurfnet = rpcUrl === SURFNET_RPC_URL$1;
32645
+ if (isSurfnet) {
32646
+ // For Surfnet: sign with signTransactionRaw, then sendRawTransaction
32647
+ const signedTx = await this.signTransactionRaw(transaction, privyWallet);
32648
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
32649
+ const signature = await connection.sendRawTransaction(signedTx);
32650
+ return signature;
32651
+ }
32652
+ else {
32653
+ // For non-Surfnet: use Privy's combined signAndSendTransaction
32654
+ // Serialize the transaction for Privy API
32655
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
32656
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
32657
+ let serializedTx;
32658
+ if (isLegacyTransaction) {
32659
+ serializedTx = transaction.serialize({ requireAllSignatures: false, verifySignatures: false });
32311
32660
  }
32312
- // If wallet not connected, trigger connection and queue the signing
32313
- if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
32314
- return new Promise((resolve, reject) => {
32315
- this.pendingSignTransaction = {
32316
- resolve,
32317
- reject,
32318
- transaction
32319
- };
32320
- this.privyMethods.connectWallet();
32321
- // Set a timeout to reject the promise if connection takes too long
32322
- setTimeout(() => {
32323
- if (this.pendingSignTransaction) {
32324
- this.pendingSignTransaction.reject(new Error("Wallet connection timed out"));
32325
- this.pendingSignTransaction = null;
32326
- }
32327
- }, 30000); // 30 seconds timeout
32328
- });
32661
+ else {
32662
+ serializedTx = transaction.serialize();
32329
32663
  }
32330
- const serializedForSign = transaction.serialize({ requireAllSignatures: false, verifySignatures: false });
32331
- const result = await ((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.signTransaction({
32332
- transaction: serializedForSign,
32664
+ const result = await ((_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.useSendTransactionSolana.signAndSendTransaction({
32665
+ transaction: serializedTx,
32333
32666
  wallet: privyWallet,
32334
32667
  chain: this.chainId
32335
32668
  }));
32336
- // Privy returns { signedTransaction: Uint8Array }, unwrap and deserialize to match interface
32337
- const signedBytes = (result === null || result === void 0 ? void 0 : result.signedTransaction) || result;
32338
- if (signedBytes instanceof Uint8Array || Buffer.isBuffer(signedBytes)) {
32339
- // Try to deserialize as VersionedTransaction first, fall back to legacy Transaction
32340
- try {
32341
- return web3_js.VersionedTransaction.deserialize(signedBytes);
32342
- }
32343
- catch (_c) {
32344
- return web3_js.Transaction.from(signedBytes);
32345
- }
32669
+ // Handle case where signature might be bytes instead of string
32670
+ let signature = result.signature;
32671
+ if (signature instanceof Uint8Array || Array.isArray(signature)) {
32672
+ // Convert bytes to base58
32673
+ signature = bs58.encode(signature instanceof Uint8Array ? signature : new Uint8Array(signature));
32346
32674
  }
32347
- // If already a Transaction object, return as-is
32348
- return signedBytes;
32349
- }
32350
- catch (error) {
32351
- throw new Error(`Failed to sign and send serialized transaction: ${error.message}`);
32675
+ return signature;
32352
32676
  }
32353
32677
  }
32354
32678
  async signMessage(message) {
@@ -32520,6 +32844,14 @@ class MockAuthProvider {
32520
32844
  console.log('[MockAuth] Mock transaction signing (no-op)');
32521
32845
  return transaction;
32522
32846
  }
32847
+ /**
32848
+ * Sign and submit transaction - not supported in mock environment.
32849
+ * See the real providers (PhantomWalletProvider, PrivyWalletProvider, SolanaKeypairProvider)
32850
+ * for the full implementation with blockhash handling and feePayer support.
32851
+ */
32852
+ async signAndSubmitTransaction(_transaction, _feePayer) {
32853
+ throw new Error('signAndSubmitTransaction is not supported in the mock environment');
32854
+ }
32523
32855
  /**
32524
32856
  * Restore session - only restores if user previously called login() explicitly.
32525
32857
  * This prevents auto-login on first page load, but allows session persistence after login.
@@ -32597,6 +32929,16 @@ class OffchainAuthProvider {
32597
32929
  async signTransaction(tx) {
32598
32930
  return this.wrappedProvider.signTransaction(tx);
32599
32931
  }
32932
+ /**
32933
+ * Sign and submit transaction - not supported in poofnet environment.
32934
+ * See the real providers (PhantomWalletProvider, PrivyWalletProvider, SolanaKeypairProvider)
32935
+ * for the full implementation with blockhash handling and feePayer support.
32936
+ */
32937
+ async signAndSubmitTransaction(_transaction, _feePayer) {
32938
+ // Show modal explaining poofnet doesn't support real transactions
32939
+ await this.showUnsupportedTransactionModal();
32940
+ throw new Error('Poofnet does not support real Solana transactions. Deploy your project to mainnet to use this feature.');
32941
+ }
32600
32942
  async getNativeMethods() {
32601
32943
  return this.wrappedProvider.getNativeMethods();
32602
32944
  }
@@ -32629,6 +32971,99 @@ class OffchainAuthProvider {
32629
32971
  }
32630
32972
  }
32631
32973
  // ============ Modal Implementation ============
32974
+ async showUnsupportedTransactionModal() {
32975
+ return new Promise((resolve) => {
32976
+ // Create modal container
32977
+ this.modalContainer = document.createElement("div");
32978
+ this.modalContainer.id = "poofnet-unsupported-modal";
32979
+ this.modalContainer.innerHTML = this.getUnsupportedModalHTML();
32980
+ document.body.appendChild(this.modalContainer);
32981
+ // Add styles
32982
+ const style = document.createElement("style");
32983
+ style.textContent = this.getModalStyles();
32984
+ this.modalContainer.appendChild(style);
32985
+ // Mark all other body children as inert
32986
+ document.body.childNodes.forEach((child) => {
32987
+ if (child !== this.modalContainer &&
32988
+ child instanceof HTMLElement) {
32989
+ child.setAttribute("inert", "");
32990
+ }
32991
+ });
32992
+ // Animate in
32993
+ requestAnimationFrame(() => {
32994
+ var _a, _b;
32995
+ const overlay = (_a = this.modalContainer) === null || _a === void 0 ? void 0 : _a.querySelector(".poofnet-modal-overlay");
32996
+ const content = (_b = this.modalContainer) === null || _b === void 0 ? void 0 : _b.querySelector(".poofnet-modal-content");
32997
+ if (overlay)
32998
+ overlay.style.opacity = "1";
32999
+ if (content) {
33000
+ content.style.opacity = "1";
33001
+ content.style.transform = "translateY(0)";
33002
+ }
33003
+ });
33004
+ // Handle close button
33005
+ const closeBtn = this.modalContainer.querySelector("#poofnet-close-btn");
33006
+ closeBtn === null || closeBtn === void 0 ? void 0 : closeBtn.addEventListener("click", () => {
33007
+ this.closeModal();
33008
+ resolve();
33009
+ });
33010
+ // Handle cancel button
33011
+ const cancelBtn = this.modalContainer.querySelector("#poofnet-cancel-btn");
33012
+ cancelBtn === null || cancelBtn === void 0 ? void 0 : cancelBtn.addEventListener("click", () => {
33013
+ this.closeModal();
33014
+ resolve();
33015
+ });
33016
+ // Handle overlay click
33017
+ const overlay = this.modalContainer.querySelector(".poofnet-modal-overlay");
33018
+ overlay === null || overlay === void 0 ? void 0 : overlay.addEventListener("click", (e) => {
33019
+ if (e.target === overlay) {
33020
+ this.closeModal();
33021
+ resolve();
33022
+ }
33023
+ });
33024
+ // Handle escape key
33025
+ const escHandler = (e) => {
33026
+ if (e.key === "Escape") {
33027
+ document.removeEventListener("keydown", escHandler);
33028
+ this.closeModal();
33029
+ resolve();
33030
+ }
33031
+ };
33032
+ document.addEventListener("keydown", escHandler);
33033
+ });
33034
+ }
33035
+ getUnsupportedModalHTML() {
33036
+ return `
33037
+ <div class="poofnet-modal-overlay">
33038
+ <div class="poofnet-modal-content">
33039
+ <button id="poofnet-close-btn" class="poofnet-close-btn" aria-label="Close">
33040
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
33041
+ <path d="M1 1L13 13M1 13L13 1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
33042
+ </svg>
33043
+ </button>
33044
+ <div class="poofnet-modal-header">
33045
+ <div class="poofnet-modal-icon">⚠️</div>
33046
+ <h2 class="poofnet-modal-title">Transaction Not Supported</h2>
33047
+ <p class="poofnet-modal-subtitle">Poofnet Simulated Blockchain</p>
33048
+ </div>
33049
+
33050
+ <div class="poofnet-modal-body">
33051
+ <div class="poofnet-info-box" style="background: #fef3c7;">
33052
+ <span class="poofnet-info-icon">ℹ️</span>
33053
+ <span class="poofnet-info-text" style="color: #92400e;">
33054
+ Poofnet is a simulated blockchain and does not support real Solana transactions.
33055
+ Deploy your project to mainnet to test real transactions.
33056
+ </span>
33057
+ </div>
33058
+ </div>
33059
+
33060
+ <div class="poofnet-modal-footer">
33061
+ <button id="poofnet-cancel-btn" class="poofnet-btn poofnet-btn-cancel" style="flex: 1;">Close</button>
33062
+ </div>
33063
+ </div>
33064
+ </div>
33065
+ `;
33066
+ }
32632
33067
  async showTransactionModal(message) {
32633
33068
  return new Promise((resolve) => {
32634
33069
  // Parse the transaction message for display
@@ -33398,9 +33833,10 @@ exports.runQueryMany = runQueryMany;
33398
33833
  exports.set = set$1;
33399
33834
  exports.setFile = setFile;
33400
33835
  exports.setMany = setMany;
33836
+ exports.signAndSubmitTransaction = signAndSubmitTransaction;
33401
33837
  exports.signMessage = signMessage;
33402
33838
  exports.signSessionCreateMessage = signSessionCreateMessage;
33403
33839
  exports.signTransaction = signTransaction;
33404
33840
  exports.subscribe = subscribe;
33405
33841
  exports.useAuth = useAuth;
33406
- //# sourceMappingURL=index-5j5jdNNe.js.map
33842
+ //# sourceMappingURL=index-BaNlnYmn.js.map