@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.
@@ -12425,6 +12425,13 @@ async function signTransaction(transaction) {
12425
12425
  }
12426
12426
  return config.authProvider.signTransaction(transaction);
12427
12427
  }
12428
+ async function signAndSubmitTransaction(transaction, feePayer) {
12429
+ const config = await getConfig();
12430
+ if (!config.authProvider) {
12431
+ throw new Error('Auth provider not initialized. Please call init() first.');
12432
+ }
12433
+ return config.authProvider.signAndSubmitTransaction(transaction, feePayer);
12434
+ }
12428
12435
 
12429
12436
  const activeConnections = {};
12430
12437
  const responseCache = {};
@@ -12646,7 +12653,7 @@ async function loadDependencies() {
12646
12653
  const [reactModule, reactDomModule, phantomModule] = await Promise.all([
12647
12654
  import('react'),
12648
12655
  import('react-dom/client'),
12649
- import('./index-DIB1IdkM.esm.js')
12656
+ import('./index-CfbGteXj.esm.js')
12650
12657
  ]);
12651
12658
  React$1 = reactModule;
12652
12659
  ReactDOM$1 = reactDomModule;
@@ -13092,18 +13099,15 @@ class PhantomWalletProvider {
13092
13099
  await this.ensureSolanaReady();
13093
13100
  }
13094
13101
  catch (error) {
13095
- // Reconnection failed - log user out and throw
13096
13102
  console.error('Solana provider reconnection failed, logging out:', error.message);
13097
13103
  await this.logout();
13098
13104
  throw new Error('Wallet connection lost. Please reconnect.');
13099
13105
  }
13100
- // Ensure connected
13101
13106
  if (!((_a = this.phantomMethods) === null || _a === void 0 ? void 0 : _a.isConnected)) {
13102
13107
  const user = await this.login();
13103
13108
  if (!user) {
13104
13109
  throw new Error('Failed to connect wallet');
13105
13110
  }
13106
- // Wait for solana to be ready after login
13107
13111
  try {
13108
13112
  await this.ensureSolanaReady();
13109
13113
  }
@@ -13116,21 +13120,7 @@ class PhantomWalletProvider {
13116
13120
  if (!((_b = this.phantomMethods) === null || _b === void 0 ? void 0 : _b.solana)) {
13117
13121
  throw new Error('Solana signing not available');
13118
13122
  }
13119
- let rpcUrl = this.networkUrl;
13120
- if (this.networkUrl == null) {
13121
- if (solTransactionData.network === 'solana_devnet') {
13122
- rpcUrl = SOLANA_DEVNET_RPC_URL;
13123
- }
13124
- else if (solTransactionData.network === 'solana_mainnet') {
13125
- rpcUrl = SOLANA_MAINNET_RPC_URL;
13126
- }
13127
- else if (solTransactionData.network === 'surfnet') {
13128
- rpcUrl = SURFNET_RPC_URL;
13129
- }
13130
- else {
13131
- throw new Error('Invalid network for Phantom wallet');
13132
- }
13133
- }
13123
+ const rpcUrl = this.getRpcUrl(solTransactionData.network);
13134
13124
  const connection = new Connection(rpcUrl, 'confirmed');
13135
13125
  try {
13136
13126
  const remainingAccounts = convertRemainingAccounts(solTransactionData.txArgs[0].remainingAccounts);
@@ -13170,7 +13160,7 @@ class PhantomWalletProvider {
13170
13160
  finalDeduped.push(acc);
13171
13161
  }
13172
13162
  }
13173
- const { tx, blockhash, lastValidBlockHeight } = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, publicKey, {
13163
+ const { tx } = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, publicKey, {
13174
13164
  app_id,
13175
13165
  documents: solTransactionData.txArgs[0].setDocumentData,
13176
13166
  delete_paths: solTransactionData.txArgs[0].deletePaths,
@@ -13185,19 +13175,8 @@ class PhantomWalletProvider {
13185
13175
  data: ""
13186
13176
  };
13187
13177
  }
13188
- const signature = await connection.sendRawTransaction(signedTx.serialize());
13189
- const confirmation = await connection.confirmTransaction({
13190
- signature,
13191
- blockhash,
13192
- lastValidBlockHeight,
13193
- }, 'confirmed');
13194
- if (confirmation.value.err) {
13195
- throw new Error(`Transaction failed: ${confirmation.value.err.toString()}`);
13196
- }
13197
- const txInfo = await connection.getParsedTransaction(signature, {
13198
- maxSupportedTransactionVersion: 0,
13199
- commitment: 'confirmed'
13200
- });
13178
+ // Submit using shared helper
13179
+ const { signature, txInfo } = await this.submitSignedTransaction(signedTx, connection);
13201
13180
  return {
13202
13181
  transactionSignature: signature,
13203
13182
  blockNumber: (txInfo === null || txInfo === void 0 ? void 0 : txInfo.slot) || 0,
@@ -13223,6 +13202,16 @@ class PhantomWalletProvider {
13223
13202
  throw new Error(`Failed to execute transaction: ${error.message}`);
13224
13203
  }
13225
13204
  }
13205
+ /**
13206
+ * Signs a Solana transaction without submitting it.
13207
+ *
13208
+ * This method handles blockhash automatically if not set - you do NOT need to
13209
+ * set recentBlockhash on the transaction before calling this method.
13210
+ * The network/RPC URL is derived from the provider's configuration (set during initialization).
13211
+ *
13212
+ * @param transaction - The transaction to sign (Transaction or VersionedTransaction)
13213
+ * @returns The signed transaction
13214
+ */
13226
13215
  async signTransaction(transaction) {
13227
13216
  var _a, _b, _c, _d;
13228
13217
  try {
@@ -13251,6 +13240,36 @@ class PhantomWalletProvider {
13251
13240
  if (!((_b = this.phantomMethods) === null || _b === void 0 ? void 0 : _b.solana)) {
13252
13241
  throw new Error('Solana signing not available');
13253
13242
  }
13243
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
13244
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
13245
+ // Ensure blockhash is set before signing
13246
+ if (isLegacyTransaction) {
13247
+ const legacyTx = transaction;
13248
+ if (!legacyTx.recentBlockhash) {
13249
+ const rpcUrl = this.getRpcUrl();
13250
+ const connection = new Connection(rpcUrl, 'confirmed');
13251
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
13252
+ legacyTx.recentBlockhash = blockhash;
13253
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
13254
+ }
13255
+ // Set feePayer if not already set
13256
+ if (!legacyTx.feePayer) {
13257
+ const solAddress = this.phantomMethods.addresses.find((addr) => addr.addressType === phantomReactSdk.AddressType.solana);
13258
+ if (solAddress) {
13259
+ legacyTx.feePayer = new PublicKey(solAddress.address);
13260
+ }
13261
+ }
13262
+ }
13263
+ else {
13264
+ // VersionedTransaction
13265
+ const versionedTx = transaction;
13266
+ if (!versionedTx.message.recentBlockhash) {
13267
+ const rpcUrl = this.getRpcUrl();
13268
+ const connection = new Connection(rpcUrl, 'confirmed');
13269
+ const { blockhash } = await connection.getLatestBlockhash('confirmed');
13270
+ versionedTx.message.recentBlockhash = blockhash;
13271
+ }
13272
+ }
13254
13273
  try {
13255
13274
  return await this.phantomMethods.solana.signTransaction(transaction);
13256
13275
  }
@@ -13264,6 +13283,102 @@ class PhantomWalletProvider {
13264
13283
  throw new Error(`Failed to sign transaction: ${error.message}`);
13265
13284
  }
13266
13285
  }
13286
+ /**
13287
+ * Signs and submits a Solana transaction to the network.
13288
+ *
13289
+ * This method handles blockhash and transaction confirmation automatically - you do NOT need to
13290
+ * set recentBlockhash or lastValidBlockHeight on the transaction before calling this method.
13291
+ * The network/RPC URL is derived from the provider's configuration (set during initialization).
13292
+ *
13293
+ * @param transaction - The transaction to sign and submit (Transaction or VersionedTransaction)
13294
+ * @param feePayer - Optional fee payer public key. If not provided and the transaction doesn't
13295
+ * already have a feePayer set, the connected wallet address will be used.
13296
+ * Useful for co-signing scenarios where a different account pays the fees.
13297
+ * @returns The transaction signature
13298
+ */
13299
+ async signAndSubmitTransaction(transaction, feePayer) {
13300
+ var _a, _b, _c, _d, _e, _f, _g, _h;
13301
+ try {
13302
+ await this.ensureSolanaReady();
13303
+ }
13304
+ catch (error) {
13305
+ console.error('Solana provider reconnection failed, logging out:', error.message);
13306
+ await this.logout();
13307
+ throw new Error('Wallet connection lost. Please reconnect.');
13308
+ }
13309
+ if (!((_a = this.phantomMethods) === null || _a === void 0 ? void 0 : _a.isConnected)) {
13310
+ const user = await this.login();
13311
+ if (!user) {
13312
+ throw new Error('Failed to connect wallet');
13313
+ }
13314
+ try {
13315
+ await this.ensureSolanaReady();
13316
+ }
13317
+ catch (error) {
13318
+ console.error('Solana provider reconnection failed after login, logging out:', error.message);
13319
+ await this.logout();
13320
+ throw new Error('Wallet connection lost. Please reconnect.');
13321
+ }
13322
+ }
13323
+ if (!((_b = this.phantomMethods) === null || _b === void 0 ? void 0 : _b.solana)) {
13324
+ throw new Error('Solana signing not available');
13325
+ }
13326
+ const rpcUrl = this.getRpcUrl();
13327
+ const connection = new Connection(rpcUrl, 'confirmed');
13328
+ try {
13329
+ // Get fresh blockhash and set it on the transaction before signing
13330
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
13331
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
13332
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
13333
+ if (isLegacyTransaction) {
13334
+ const legacyTx = transaction;
13335
+ legacyTx.recentBlockhash = blockhash;
13336
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
13337
+ // Set feePayer if not already set
13338
+ if (!legacyTx.feePayer) {
13339
+ if (feePayer) {
13340
+ legacyTx.feePayer = feePayer;
13341
+ }
13342
+ else {
13343
+ // Use connected wallet address as feePayer
13344
+ const solAddress = this.phantomMethods.addresses.find((addr) => addr.addressType === phantomReactSdk.AddressType.solana);
13345
+ if (solAddress) {
13346
+ legacyTx.feePayer = new PublicKey(solAddress.address);
13347
+ }
13348
+ }
13349
+ }
13350
+ }
13351
+ else {
13352
+ // VersionedTransaction
13353
+ const versionedTx = transaction;
13354
+ versionedTx.message.recentBlockhash = blockhash;
13355
+ // Note: VersionedTransaction feePayer is set in the message at creation time
13356
+ // and cannot be modified after creation
13357
+ }
13358
+ // Sign the transaction
13359
+ const signedTx = await this.phantomMethods.solana.signTransaction(transaction);
13360
+ // Submit using shared helper with the blockhash we set
13361
+ const { signature } = await this.submitSignedTransactionWithBlockhash(signedTx, connection, blockhash, lastValidBlockHeight);
13362
+ return signature;
13363
+ }
13364
+ catch (error) {
13365
+ // Check if this is a connection error - if so, log out
13366
+ 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'))) {
13367
+ console.error('Solana provider connection lost during transaction, logging out');
13368
+ await this.logout();
13369
+ throw new Error('Wallet connection lost. Please reconnect.');
13370
+ }
13371
+ const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
13372
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user rejected')) ||
13373
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user denied')) ||
13374
+ ((_g = error === null || error === void 0 ? void 0 : error.message) === null || _g === void 0 ? void 0 : _g.toLowerCase().includes('user cancelled')) ||
13375
+ ((_h = error === null || error === void 0 ? void 0 : error.message) === null || _h === void 0 ? void 0 : _h.toLowerCase().includes('user canceled'));
13376
+ if (!isUserRejection) {
13377
+ console.error('Failed to execute transaction', error);
13378
+ }
13379
+ throw new Error(`Failed to execute transaction: ${error.message}`);
13380
+ }
13381
+ }
13267
13382
  async signMessage(message) {
13268
13383
  var _a, _b, _c, _d, _e, _f, _g, _h;
13269
13384
  try {
@@ -13334,6 +13449,50 @@ class PhantomWalletProvider {
13334
13449
  await this.ensureReady();
13335
13450
  return this.phantomMethods;
13336
13451
  }
13452
+ /* ----------------------------------------------------------- *
13453
+ * Private Helpers
13454
+ * ----------------------------------------------------------- */
13455
+ getRpcUrl(network) {
13456
+ if (this.networkUrl) {
13457
+ return this.networkUrl;
13458
+ }
13459
+ if (network === 'solana_devnet') {
13460
+ return SOLANA_DEVNET_RPC_URL;
13461
+ }
13462
+ else if (network === 'solana_mainnet') {
13463
+ return SOLANA_MAINNET_RPC_URL;
13464
+ }
13465
+ else if (network === 'surfnet') {
13466
+ return SURFNET_RPC_URL;
13467
+ }
13468
+ return SOLANA_MAINNET_RPC_URL; // default to mainnet
13469
+ }
13470
+ async submitSignedTransaction(signedTx, connection) {
13471
+ // Get fresh blockhash for confirmation
13472
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
13473
+ return this.submitSignedTransactionWithBlockhash(signedTx, connection, blockhash, lastValidBlockHeight);
13474
+ }
13475
+ async submitSignedTransactionWithBlockhash(signedTx, connection, blockhash, lastValidBlockHeight) {
13476
+ // Submit the transaction
13477
+ const signature = await connection.sendRawTransaction(signedTx.serialize(), {
13478
+ preflightCommitment: 'confirmed'
13479
+ });
13480
+ // Confirm using blockhash strategy (same as runTransaction)
13481
+ const confirmation = await connection.confirmTransaction({
13482
+ signature,
13483
+ blockhash,
13484
+ lastValidBlockHeight,
13485
+ }, 'confirmed');
13486
+ if (confirmation.value.err) {
13487
+ throw new Error(`Transaction failed: ${confirmation.value.err.toString()}`);
13488
+ }
13489
+ // Get transaction info
13490
+ const txInfo = await connection.getParsedTransaction(signature, {
13491
+ maxSupportedTransactionVersion: 0,
13492
+ commitment: 'confirmed'
13493
+ });
13494
+ return { signature, txInfo };
13495
+ }
13337
13496
  }
13338
13497
  PhantomWalletProvider.instance = null;
13339
13498
 
@@ -31845,6 +32004,8 @@ class PrivyWalletProvider {
31845
32004
  this.pendingSignTransaction = null;
31846
32005
  // This is used to store pending signMessage calls until the wallet is connected
31847
32006
  this.pendingSignMessage = null;
32007
+ // This is used to store pending signAndSubmitTransaction calls until the wallet is connected
32008
+ this.pendingSignAndSubmitTransaction = null;
31848
32009
  this.networkUrl = networkUrl;
31849
32010
  if (typeof window === 'undefined') {
31850
32011
  throw new Error('PrivyWalletProvider can only be instantiated in a browser environment');
@@ -31961,6 +32122,18 @@ class PrivyWalletProvider {
31961
32122
  }
31962
32123
  that.pendingSignMessage = null;
31963
32124
  }
32125
+ // If there's a pending signAndSubmitTransaction, execute it now
32126
+ if (that.pendingSignAndSubmitTransaction) {
32127
+ const { transaction, feePayer, resolve, reject } = that.pendingSignAndSubmitTransaction;
32128
+ try {
32129
+ const result = await that.signAndSubmitTransaction(transaction, feePayer);
32130
+ resolve(result);
32131
+ }
32132
+ catch (error) {
32133
+ reject(error);
32134
+ }
32135
+ that.pendingSignAndSubmitTransaction = null;
32136
+ }
31964
32137
  },
31965
32138
  onError: (error) => {
31966
32139
  // Only log errors that aren't user-initiated cancellations
@@ -31979,6 +32152,10 @@ class PrivyWalletProvider {
31979
32152
  that.pendingSignMessage.reject(error);
31980
32153
  that.pendingSignMessage = null;
31981
32154
  }
32155
+ if (that.pendingSignAndSubmitTransaction) {
32156
+ that.pendingSignAndSubmitTransaction.reject(error);
32157
+ that.pendingSignAndSubmitTransaction = null;
32158
+ }
31982
32159
  }
31983
32160
  });
31984
32161
  const { login } = privyImports.useLogin({
@@ -32125,7 +32302,7 @@ class PrivyWalletProvider {
32125
32302
  await this.privyMethods.logout();
32126
32303
  }
32127
32304
  async runTransaction(_evmTransactionData, solTransactionData, options) {
32128
- var _a, _b, _c, _d;
32305
+ var _a;
32129
32306
  await this.ensureReady();
32130
32307
  let session = await WebSessionManager.getSession();
32131
32308
  let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
@@ -32160,21 +32337,7 @@ class PrivyWalletProvider {
32160
32337
  if (solTransactionData == null) {
32161
32338
  throw new Error("Solana transaction data is required");
32162
32339
  }
32163
- let rpcUrl = this.networkUrl;
32164
- if (this.networkUrl == null) {
32165
- if (solTransactionData.network === 'solana_devnet') {
32166
- rpcUrl = SOLANA_DEVNET_RPC_URL;
32167
- }
32168
- else if (solTransactionData.network === 'solana_mainnet') {
32169
- rpcUrl = SOLANA_MAINNET_RPC_URL;
32170
- }
32171
- else if (solTransactionData.network === 'surfnet') {
32172
- rpcUrl = SURFNET_RPC_URL$1;
32173
- }
32174
- else {
32175
- throw new Error('Invalid network for Phantom wallet');
32176
- }
32177
- }
32340
+ const rpcUrl = this.getRpcUrl(solTransactionData.network);
32178
32341
  const connection = new Connection(rpcUrl, "confirmed");
32179
32342
  const remainingAccounts = convertRemainingAccounts(solTransactionData.txArgs[0].remainingAccounts);
32180
32343
  let app_id = solTransactionData.appId;
@@ -32200,71 +32363,28 @@ class PrivyWalletProvider {
32200
32363
  }
32201
32364
  }
32202
32365
  const { tx, blockhash, lastValidBlockHeight } = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, new 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);
32203
- if (tx instanceof Transaction) {
32366
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
32367
+ const isLegacyTx = 'recentBlockhash' in tx && !('message' in tx && 'staticAccountKeys' in tx.message);
32368
+ if (isLegacyTx) {
32204
32369
  tx.recentBlockhash = blockhash;
32205
32370
  tx.lastValidBlockHeight = lastValidBlockHeight;
32206
32371
  }
32207
- else if (tx instanceof VersionedTransaction) {
32372
+ else {
32208
32373
  tx.message.recentBlockhash = blockhash;
32209
32374
  }
32210
32375
  try {
32211
32376
  if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
32212
- // v3 API: serialize transaction and pass wallet/chain
32213
- let serializedTx;
32214
- if (tx instanceof Transaction) {
32215
- serializedTx = tx.serialize({ requireAllSignatures: false, verifySignatures: false });
32216
- }
32217
- else {
32218
- serializedTx = tx.serialize();
32219
- }
32220
- const signedTx = await ((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.signTransaction({
32221
- transaction: serializedTx,
32222
- wallet: privyWallet,
32223
- chain: this.chainId
32224
- }));
32377
+ // Just sign, don't submit - return raw signed bytes (same as original runTransaction)
32378
+ const signedTx = await this.signTransactionRaw(tx, privyWallet);
32225
32379
  return {
32226
- signedTransaction: signedTx,
32380
+ signedTransaction: signedTx, // Raw Uint8Array from Privy
32227
32381
  blockNumber: 0,
32228
32382
  gasUsed: "0",
32229
32383
  data: ""
32230
32384
  };
32231
32385
  }
32232
- const isSurfnet = connection.rpcEndpoint === SURFNET_RPC_URL$1;
32233
- let txSignature;
32234
- if (isSurfnet) {
32235
- // v3 API: serialize transaction and pass wallet/chain
32236
- let serializedForSign;
32237
- if (tx instanceof Transaction) {
32238
- serializedForSign = tx.serialize({ requireAllSignatures: false, verifySignatures: false });
32239
- }
32240
- else {
32241
- serializedForSign = tx.serialize();
32242
- }
32243
- const signedTx = await ((_c = this.privyMethods) === null || _c === void 0 ? void 0 : _c.signTransaction({
32244
- transaction: serializedForSign,
32245
- wallet: privyWallet,
32246
- chain: this.chainId
32247
- }));
32248
- txSignature = await connection.sendRawTransaction(signedTx);
32249
- }
32250
- else {
32251
- // v3 API: transaction must be Uint8Array, pass wallet object
32252
- // Serialize without requiring signatures - Privy will sign it
32253
- let serializedTx;
32254
- if (tx instanceof Transaction) {
32255
- serializedTx = tx.serialize({ requireAllSignatures: false, verifySignatures: false });
32256
- }
32257
- else {
32258
- // VersionedTransaction
32259
- serializedTx = tx.serialize();
32260
- }
32261
- const result = await ((_d = this.privyMethods) === null || _d === void 0 ? void 0 : _d.useSendTransactionSolana.signAndSendTransaction({
32262
- transaction: serializedTx,
32263
- wallet: privyWallet,
32264
- chain: this.chainId
32265
- }));
32266
- txSignature = result.signature;
32267
- }
32386
+ // Sign and submit using shared helper
32387
+ const txSignature = await this.signAndSubmitInternal(tx, privyWallet, rpcUrl);
32268
32388
  return {
32269
32389
  transactionSignature: txSignature,
32270
32390
  blockNumber: 0,
@@ -32277,58 +32397,262 @@ class PrivyWalletProvider {
32277
32397
  throw err;
32278
32398
  }
32279
32399
  }
32400
+ /**
32401
+ * Signs a Solana transaction without submitting it.
32402
+ *
32403
+ * This method handles blockhash automatically if not set - you do NOT need to
32404
+ * set recentBlockhash on the transaction before calling this method.
32405
+ * The network/RPC URL is derived from the provider's configuration (set during initialization).
32406
+ *
32407
+ * @param transaction - The transaction to sign (Transaction or VersionedTransaction)
32408
+ * @returns The signed transaction
32409
+ */
32280
32410
  async signTransaction(transaction) {
32281
- var _a, _b;
32411
+ var _a;
32412
+ await this.ensureReady();
32413
+ let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
32414
+ let session = await WebSessionManager.getSession();
32415
+ let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
32416
+ let privyWallet = privyWallets === null || privyWallets === void 0 ? void 0 : privyWallets.find((wallet) => wallet.address === sessionAddress);
32417
+ // If there's already a pending sign transaction, throw an error to prevent overlapping calls
32418
+ if (this.pendingSignTransaction) {
32419
+ throw new Error("Oops... something went wrong. Please try again.");
32420
+ }
32421
+ // If wallet not connected, trigger connection and queue the signing
32422
+ if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
32423
+ return new Promise((resolve, reject) => {
32424
+ this.pendingSignTransaction = {
32425
+ resolve,
32426
+ reject,
32427
+ transaction
32428
+ };
32429
+ this.privyMethods.connectWallet();
32430
+ // Set a timeout to reject the promise if connection takes too long
32431
+ setTimeout(() => {
32432
+ if (this.pendingSignTransaction) {
32433
+ this.pendingSignTransaction.reject(new Error("Wallet connection timed out"));
32434
+ this.pendingSignTransaction = null;
32435
+ }
32436
+ }, 30000); // 30 seconds timeout
32437
+ });
32438
+ }
32439
+ // Privy requires serialized transaction bytes, which requires a blockhash.
32440
+ // If the transaction doesn't have one, get a fresh blockhash and set it.
32441
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
32442
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
32443
+ if (isLegacyTransaction) {
32444
+ const legacyTx = transaction;
32445
+ if (!legacyTx.recentBlockhash) {
32446
+ const rpcUrl = this.getRpcUrl();
32447
+ const connection = new Connection(rpcUrl, 'confirmed');
32448
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
32449
+ legacyTx.recentBlockhash = blockhash;
32450
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
32451
+ }
32452
+ // Set feePayer if not already set
32453
+ if (!legacyTx.feePayer) {
32454
+ legacyTx.feePayer = new PublicKey(privyWallet.address);
32455
+ }
32456
+ }
32457
+ else {
32458
+ // VersionedTransaction
32459
+ const versionedTx = transaction;
32460
+ if (!versionedTx.message.recentBlockhash) {
32461
+ const rpcUrl = this.getRpcUrl();
32462
+ const connection = new Connection(rpcUrl, 'confirmed');
32463
+ const { blockhash } = await connection.getLatestBlockhash('confirmed');
32464
+ versionedTx.message.recentBlockhash = blockhash;
32465
+ }
32466
+ }
32467
+ // Sign using raw method, then deserialize for the public API
32468
+ const signedTxRaw = await this.signTransactionRaw(transaction, privyWallet);
32469
+ return this.deserializeSignedTransaction(signedTxRaw);
32470
+ }
32471
+ /**
32472
+ * Signs and submits a Solana transaction to the network.
32473
+ *
32474
+ * This method handles blockhash and transaction confirmation automatically - you do NOT need to
32475
+ * set recentBlockhash or lastValidBlockHeight on the transaction before calling this method.
32476
+ * The network/RPC URL is derived from the provider's configuration (set during initialization).
32477
+ *
32478
+ * @param transaction - The transaction to sign and submit (Transaction or VersionedTransaction)
32479
+ * @param feePayer - Optional fee payer public key. If not provided and the transaction doesn't
32480
+ * already have a feePayer set, the connected wallet address will be used.
32481
+ * Useful for co-signing scenarios where a different account pays the fees.
32482
+ * @returns The transaction signature
32483
+ */
32484
+ async signAndSubmitTransaction(transaction, feePayer) {
32485
+ var _a;
32486
+ await this.ensureReady();
32487
+ let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
32488
+ let session = await WebSessionManager.getSession();
32489
+ let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
32490
+ let privyWallet = privyWallets === null || privyWallets === void 0 ? void 0 : privyWallets.find((wallet) => wallet.address === sessionAddress);
32491
+ // If there's already a pending signAndSubmitTransaction, throw an error to prevent overlapping calls
32492
+ if (this.pendingSignAndSubmitTransaction) {
32493
+ throw new Error("Oops... something went wrong. Please try again.");
32494
+ }
32495
+ // If wallet not connected, trigger connection and queue the signing
32496
+ if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
32497
+ return new Promise((resolve, reject) => {
32498
+ this.pendingSignAndSubmitTransaction = {
32499
+ resolve,
32500
+ reject,
32501
+ transaction,
32502
+ feePayer
32503
+ };
32504
+ this.privyMethods.connectWallet();
32505
+ // Set a timeout to reject the promise if connection takes too long
32506
+ setTimeout(() => {
32507
+ if (this.pendingSignAndSubmitTransaction) {
32508
+ this.pendingSignAndSubmitTransaction.reject(new Error("Wallet connection timed out"));
32509
+ this.pendingSignAndSubmitTransaction = null;
32510
+ }
32511
+ }, 30000); // 30 seconds timeout
32512
+ });
32513
+ }
32514
+ // Get RPC URL and create connection
32515
+ const rpcUrl = this.getRpcUrl();
32516
+ const connection = new Connection(rpcUrl, 'confirmed');
32517
+ // Get fresh blockhash and set it on the transaction before signing
32518
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
32519
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
32520
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
32521
+ if (isLegacyTransaction) {
32522
+ const legacyTx = transaction;
32523
+ legacyTx.recentBlockhash = blockhash;
32524
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
32525
+ // Set feePayer if not already set
32526
+ if (!legacyTx.feePayer) {
32527
+ legacyTx.feePayer = feePayer !== null && feePayer !== void 0 ? feePayer : new PublicKey(privyWallet.address);
32528
+ }
32529
+ }
32530
+ else {
32531
+ // VersionedTransaction
32532
+ const versionedTx = transaction;
32533
+ versionedTx.message.recentBlockhash = blockhash;
32534
+ // Note: VersionedTransaction feePayer is set in the message at creation time
32535
+ // and cannot be modified after creation
32536
+ }
32537
+ // Use shared sign and submit logic
32538
+ return this.signAndSubmitInternal(transaction, privyWallet, rpcUrl);
32539
+ }
32540
+ // ============ Private Helpers ============
32541
+ getRpcUrl(network) {
32542
+ if (this.networkUrl) {
32543
+ return this.networkUrl;
32544
+ }
32545
+ if (network === 'solana_devnet') {
32546
+ return SOLANA_DEVNET_RPC_URL;
32547
+ }
32548
+ else if (network === 'solana_mainnet') {
32549
+ return SOLANA_MAINNET_RPC_URL;
32550
+ }
32551
+ else if (network === 'surfnet') {
32552
+ return SURFNET_RPC_URL$1;
32553
+ }
32554
+ return SOLANA_MAINNET_RPC_URL; // default to mainnet
32555
+ }
32556
+ /**
32557
+ * Internal sign transaction - serializes and signs via Privy
32558
+ * Returns the raw result from Privy (Uint8Array)
32559
+ * This mirrors exactly what runTransaction was doing
32560
+ */
32561
+ async signTransactionRaw(transaction, privyWallet) {
32562
+ var _a;
32563
+ // Serialize the transaction
32564
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
32565
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
32566
+ let serializedForSign;
32567
+ if (isLegacyTransaction) {
32568
+ serializedForSign = transaction.serialize({ requireAllSignatures: false, verifySignatures: false });
32569
+ }
32570
+ else {
32571
+ serializedForSign = transaction.serialize();
32572
+ }
32573
+ // Sign via Privy - returns { signedTransaction: Uint8Array }
32574
+ const result = await ((_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.signTransaction({
32575
+ transaction: serializedForSign,
32576
+ wallet: privyWallet,
32577
+ chain: this.chainId
32578
+ }));
32579
+ // Privy returns { signedTransaction: Uint8Array }, unwrap it
32580
+ const signedTx = (result === null || result === void 0 ? void 0 : result.signedTransaction) || result;
32581
+ return signedTx;
32582
+ }
32583
+ /**
32584
+ * Deserialize a signed transaction from Uint8Array to Transaction object
32585
+ */
32586
+ deserializeSignedTransaction(signedTxRaw) {
32587
+ // Handle different formats Privy might return
32588
+ let signedTx;
32589
+ if (signedTxRaw instanceof Uint8Array) {
32590
+ signedTx = signedTxRaw;
32591
+ }
32592
+ else if (Array.isArray(signedTxRaw)) {
32593
+ signedTx = new Uint8Array(signedTxRaw);
32594
+ }
32595
+ else if (signedTxRaw && typeof signedTxRaw === 'object' && 'signedTransaction' in signedTxRaw) {
32596
+ // Privy might wrap the result
32597
+ signedTx = signedTxRaw.signedTransaction instanceof Uint8Array
32598
+ ? signedTxRaw.signedTransaction
32599
+ : new Uint8Array(signedTxRaw.signedTransaction);
32600
+ }
32601
+ else if (Buffer.isBuffer(signedTxRaw)) {
32602
+ signedTx = new Uint8Array(signedTxRaw);
32603
+ }
32604
+ else {
32605
+ throw new Error(`Unexpected signed transaction format: ${typeof signedTxRaw}`);
32606
+ }
32607
+ // Try to deserialize as VersionedTransaction first, fall back to legacy Transaction
32282
32608
  try {
32283
- await this.ensureReady();
32284
- let privyWallets = (_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.wallets;
32285
- let session = await WebSessionManager.getSession();
32286
- let sessionAddress = session === null || session === void 0 ? void 0 : session.address;
32287
- let privyWallet = privyWallets === null || privyWallets === void 0 ? void 0 : privyWallets.find((wallet) => wallet.address === sessionAddress);
32288
- // If there's already a pending sign transaction, throw an error to prevent overlapping calls
32289
- if (this.pendingSignTransaction) {
32290
- throw new Error("Oops... something went wrong. Please try again.");
32609
+ return VersionedTransaction.deserialize(signedTx);
32610
+ }
32611
+ catch (_a) {
32612
+ return Transaction.from(signedTx);
32613
+ }
32614
+ }
32615
+ /**
32616
+ * Internal sign and submit - handles Surfnet vs non-Surfnet logic
32617
+ * This is the core submission logic used by both signAndSubmitTransaction and runTransaction
32618
+ *
32619
+ * For Surfnet: sign with signTransactionRaw, then sendRawTransaction
32620
+ * For non-Surfnet: use Privy's signAndSendTransaction (combined operation)
32621
+ */
32622
+ async signAndSubmitInternal(transaction, privyWallet, rpcUrl) {
32623
+ var _a;
32624
+ const isSurfnet = rpcUrl === SURFNET_RPC_URL$1;
32625
+ if (isSurfnet) {
32626
+ // For Surfnet: sign with signTransactionRaw, then sendRawTransaction
32627
+ const signedTx = await this.signTransactionRaw(transaction, privyWallet);
32628
+ const connection = new Connection(rpcUrl, 'confirmed');
32629
+ const signature = await connection.sendRawTransaction(signedTx);
32630
+ return signature;
32631
+ }
32632
+ else {
32633
+ // For non-Surfnet: use Privy's combined signAndSendTransaction
32634
+ // Serialize the transaction for Privy API
32635
+ // Use duck typing instead of instanceof to handle multiple @solana/web3.js versions
32636
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
32637
+ let serializedTx;
32638
+ if (isLegacyTransaction) {
32639
+ serializedTx = transaction.serialize({ requireAllSignatures: false, verifySignatures: false });
32291
32640
  }
32292
- // If wallet not connected, trigger connection and queue the signing
32293
- if (!privyWallets || privyWallets.length === 0 || !privyWallet) {
32294
- return new Promise((resolve, reject) => {
32295
- this.pendingSignTransaction = {
32296
- resolve,
32297
- reject,
32298
- transaction
32299
- };
32300
- this.privyMethods.connectWallet();
32301
- // Set a timeout to reject the promise if connection takes too long
32302
- setTimeout(() => {
32303
- if (this.pendingSignTransaction) {
32304
- this.pendingSignTransaction.reject(new Error("Wallet connection timed out"));
32305
- this.pendingSignTransaction = null;
32306
- }
32307
- }, 30000); // 30 seconds timeout
32308
- });
32641
+ else {
32642
+ serializedTx = transaction.serialize();
32309
32643
  }
32310
- const serializedForSign = transaction.serialize({ requireAllSignatures: false, verifySignatures: false });
32311
- const result = await ((_b = this.privyMethods) === null || _b === void 0 ? void 0 : _b.signTransaction({
32312
- transaction: serializedForSign,
32644
+ const result = await ((_a = this.privyMethods) === null || _a === void 0 ? void 0 : _a.useSendTransactionSolana.signAndSendTransaction({
32645
+ transaction: serializedTx,
32313
32646
  wallet: privyWallet,
32314
32647
  chain: this.chainId
32315
32648
  }));
32316
- // Privy returns { signedTransaction: Uint8Array }, unwrap and deserialize to match interface
32317
- const signedBytes = (result === null || result === void 0 ? void 0 : result.signedTransaction) || result;
32318
- if (signedBytes instanceof Uint8Array || Buffer.isBuffer(signedBytes)) {
32319
- // Try to deserialize as VersionedTransaction first, fall back to legacy Transaction
32320
- try {
32321
- return VersionedTransaction.deserialize(signedBytes);
32322
- }
32323
- catch (_c) {
32324
- return Transaction.from(signedBytes);
32325
- }
32649
+ // Handle case where signature might be bytes instead of string
32650
+ let signature = result.signature;
32651
+ if (signature instanceof Uint8Array || Array.isArray(signature)) {
32652
+ // Convert bytes to base58
32653
+ signature = bs58.encode(signature instanceof Uint8Array ? signature : new Uint8Array(signature));
32326
32654
  }
32327
- // If already a Transaction object, return as-is
32328
- return signedBytes;
32329
- }
32330
- catch (error) {
32331
- throw new Error(`Failed to sign and send serialized transaction: ${error.message}`);
32655
+ return signature;
32332
32656
  }
32333
32657
  }
32334
32658
  async signMessage(message) {
@@ -32500,6 +32824,14 @@ class MockAuthProvider {
32500
32824
  console.log('[MockAuth] Mock transaction signing (no-op)');
32501
32825
  return transaction;
32502
32826
  }
32827
+ /**
32828
+ * Sign and submit transaction - not supported in mock environment.
32829
+ * See the real providers (PhantomWalletProvider, PrivyWalletProvider, SolanaKeypairProvider)
32830
+ * for the full implementation with blockhash handling and feePayer support.
32831
+ */
32832
+ async signAndSubmitTransaction(_transaction, _feePayer) {
32833
+ throw new Error('signAndSubmitTransaction is not supported in the mock environment');
32834
+ }
32503
32835
  /**
32504
32836
  * Restore session - only restores if user previously called login() explicitly.
32505
32837
  * This prevents auto-login on first page load, but allows session persistence after login.
@@ -32577,6 +32909,16 @@ class OffchainAuthProvider {
32577
32909
  async signTransaction(tx) {
32578
32910
  return this.wrappedProvider.signTransaction(tx);
32579
32911
  }
32912
+ /**
32913
+ * Sign and submit transaction - not supported in poofnet environment.
32914
+ * See the real providers (PhantomWalletProvider, PrivyWalletProvider, SolanaKeypairProvider)
32915
+ * for the full implementation with blockhash handling and feePayer support.
32916
+ */
32917
+ async signAndSubmitTransaction(_transaction, _feePayer) {
32918
+ // Show modal explaining poofnet doesn't support real transactions
32919
+ await this.showUnsupportedTransactionModal();
32920
+ throw new Error('Poofnet does not support real Solana transactions. Deploy your project to mainnet to use this feature.');
32921
+ }
32580
32922
  async getNativeMethods() {
32581
32923
  return this.wrappedProvider.getNativeMethods();
32582
32924
  }
@@ -32609,6 +32951,99 @@ class OffchainAuthProvider {
32609
32951
  }
32610
32952
  }
32611
32953
  // ============ Modal Implementation ============
32954
+ async showUnsupportedTransactionModal() {
32955
+ return new Promise((resolve) => {
32956
+ // Create modal container
32957
+ this.modalContainer = document.createElement("div");
32958
+ this.modalContainer.id = "poofnet-unsupported-modal";
32959
+ this.modalContainer.innerHTML = this.getUnsupportedModalHTML();
32960
+ document.body.appendChild(this.modalContainer);
32961
+ // Add styles
32962
+ const style = document.createElement("style");
32963
+ style.textContent = this.getModalStyles();
32964
+ this.modalContainer.appendChild(style);
32965
+ // Mark all other body children as inert
32966
+ document.body.childNodes.forEach((child) => {
32967
+ if (child !== this.modalContainer &&
32968
+ child instanceof HTMLElement) {
32969
+ child.setAttribute("inert", "");
32970
+ }
32971
+ });
32972
+ // Animate in
32973
+ requestAnimationFrame(() => {
32974
+ var _a, _b;
32975
+ const overlay = (_a = this.modalContainer) === null || _a === void 0 ? void 0 : _a.querySelector(".poofnet-modal-overlay");
32976
+ const content = (_b = this.modalContainer) === null || _b === void 0 ? void 0 : _b.querySelector(".poofnet-modal-content");
32977
+ if (overlay)
32978
+ overlay.style.opacity = "1";
32979
+ if (content) {
32980
+ content.style.opacity = "1";
32981
+ content.style.transform = "translateY(0)";
32982
+ }
32983
+ });
32984
+ // Handle close button
32985
+ const closeBtn = this.modalContainer.querySelector("#poofnet-close-btn");
32986
+ closeBtn === null || closeBtn === void 0 ? void 0 : closeBtn.addEventListener("click", () => {
32987
+ this.closeModal();
32988
+ resolve();
32989
+ });
32990
+ // Handle cancel button
32991
+ const cancelBtn = this.modalContainer.querySelector("#poofnet-cancel-btn");
32992
+ cancelBtn === null || cancelBtn === void 0 ? void 0 : cancelBtn.addEventListener("click", () => {
32993
+ this.closeModal();
32994
+ resolve();
32995
+ });
32996
+ // Handle overlay click
32997
+ const overlay = this.modalContainer.querySelector(".poofnet-modal-overlay");
32998
+ overlay === null || overlay === void 0 ? void 0 : overlay.addEventListener("click", (e) => {
32999
+ if (e.target === overlay) {
33000
+ this.closeModal();
33001
+ resolve();
33002
+ }
33003
+ });
33004
+ // Handle escape key
33005
+ const escHandler = (e) => {
33006
+ if (e.key === "Escape") {
33007
+ document.removeEventListener("keydown", escHandler);
33008
+ this.closeModal();
33009
+ resolve();
33010
+ }
33011
+ };
33012
+ document.addEventListener("keydown", escHandler);
33013
+ });
33014
+ }
33015
+ getUnsupportedModalHTML() {
33016
+ return `
33017
+ <div class="poofnet-modal-overlay">
33018
+ <div class="poofnet-modal-content">
33019
+ <button id="poofnet-close-btn" class="poofnet-close-btn" aria-label="Close">
33020
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
33021
+ <path d="M1 1L13 13M1 13L13 1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
33022
+ </svg>
33023
+ </button>
33024
+ <div class="poofnet-modal-header">
33025
+ <div class="poofnet-modal-icon">⚠️</div>
33026
+ <h2 class="poofnet-modal-title">Transaction Not Supported</h2>
33027
+ <p class="poofnet-modal-subtitle">Poofnet Simulated Blockchain</p>
33028
+ </div>
33029
+
33030
+ <div class="poofnet-modal-body">
33031
+ <div class="poofnet-info-box" style="background: #fef3c7;">
33032
+ <span class="poofnet-info-icon">ℹ️</span>
33033
+ <span class="poofnet-info-text" style="color: #92400e;">
33034
+ Poofnet is a simulated blockchain and does not support real Solana transactions.
33035
+ Deploy your project to mainnet to test real transactions.
33036
+ </span>
33037
+ </div>
33038
+ </div>
33039
+
33040
+ <div class="poofnet-modal-footer">
33041
+ <button id="poofnet-cancel-btn" class="poofnet-btn poofnet-btn-cancel" style="flex: 1;">Close</button>
33042
+ </div>
33043
+ </div>
33044
+ </div>
33045
+ `;
33046
+ }
32612
33047
  async showTransactionModal(message) {
32613
33048
  return new Promise((resolve) => {
32614
33049
  // Parse the transaction message for display
@@ -33340,5 +33775,5 @@ async function getIdToken() {
33340
33775
  return getIdToken$1(false);
33341
33776
  }
33342
33777
 
33343
- export { getIdToken as A, PrivyWalletProvider as B, buildSetDocumentsTransaction as C, DEFAULT_TEST_ADDRESS as D, EventEmitter4 as E, convertRemainingAccounts as F, createSessionWithPrivy as G, createSessionWithSignature as H, genAuthNonce as I, genSolanaMessage as J, refreshSession as K, signSessionCreateMessage as L, MockAuthProvider as M, OffchainAuthProvider as O, PhantomWalletProvider as P, ServerSessionManager as S, WebSessionManager as W, bs58 as a, bufferExports$1 as b, commonjsRequire as c, onAuthLoadingChanged as d, getAuthLoading as e, logout as f, getCurrentUser as g, getConfig as h, init as i, getAuthProvider as j, get$2 as k, login as l, setMany as m, setFile as n, onAuthStateChanged as o, getFiles as p, runQuery as q, require$$0$1 as r, set$1 as s, runQueryMany as t, runExpression as u, runExpressionMany as v, signMessage as w, signTransaction as x, subscribe as y, useAuth as z };
33344
- //# sourceMappingURL=index-CSe3WqP-.esm.js.map
33778
+ export { useAuth as A, getIdToken as B, PrivyWalletProvider as C, DEFAULT_TEST_ADDRESS as D, EventEmitter4 as E, buildSetDocumentsTransaction as F, convertRemainingAccounts as G, createSessionWithPrivy as H, createSessionWithSignature as I, genAuthNonce as J, genSolanaMessage as K, refreshSession as L, MockAuthProvider as M, signSessionCreateMessage as N, OffchainAuthProvider as O, PhantomWalletProvider as P, ServerSessionManager as S, WebSessionManager as W, bs58 as a, bufferExports$1 as b, commonjsRequire as c, onAuthLoadingChanged as d, getAuthLoading as e, logout as f, getCurrentUser as g, getConfig as h, init as i, getAuthProvider as j, get$2 as k, login as l, setMany as m, setFile as n, onAuthStateChanged as o, getFiles as p, runQuery as q, require$$0$1 as r, set$1 as s, runQueryMany as t, runExpression as u, runExpressionMany as v, signMessage as w, signTransaction as x, signAndSubmitTransaction as y, subscribe as z };
33779
+ //# sourceMappingURL=index-CK_KC-Oy.esm.js.map