@pooflabs/web 0.0.83 → 0.0.85-rc1

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.
Files changed (79) hide show
  1. package/dist/auth/providers/solana-mobile-wallet-provider.d.ts +42 -20
  2. package/dist/{index-CpaP1yGp.esm.js → index-4TKz3Mn_.esm.js} +14 -364
  3. package/dist/index-4TKz3Mn_.esm.js.map +1 -0
  4. package/dist/{index-FviRSm3S.js → index-BoWQVxMI.js} +13 -363
  5. package/dist/index-BoWQVxMI.js.map +1 -0
  6. package/dist/{index-CP_wLmYu.esm.js → index-Buu8v-Oe.esm.js} +13 -363
  7. package/dist/index-Buu8v-Oe.esm.js.map +1 -0
  8. package/dist/{index-BxXQhFLQ.js → index-C2p1Cldz.js} +14 -364
  9. package/dist/index-C2p1Cldz.js.map +1 -0
  10. package/dist/index-COF6zNCs.esm.js +6 -0
  11. package/dist/index-COF6zNCs.esm.js.map +1 -0
  12. package/dist/{index-DQWyH96R.js → index-DlyeWzMk.js} +2 -2
  13. package/dist/index-DlyeWzMk.js.map +1 -0
  14. package/dist/{index-DP0xF34Z.js → index-R7cvXys2.js} +486 -299
  15. package/dist/index-R7cvXys2.js.map +1 -0
  16. package/dist/{index-B7yaLhND.esm.js → index-ZKzq5QT_.esm.js} +487 -300
  17. package/dist/index-ZKzq5QT_.esm.js.map +1 -0
  18. package/dist/{index.browser-_zN3Uapq.js → index.browser-BQSN-6X2.js} +846 -815
  19. package/dist/index.browser-BQSN-6X2.js.map +1 -0
  20. package/dist/index.browser-DZCNegue.js +6070 -0
  21. package/dist/index.browser-DZCNegue.js.map +1 -0
  22. package/dist/{index.browser-B_wQp2A8.esm.js → index.browser-tPepE5fo.esm.js} +836 -802
  23. package/dist/index.browser-tPepE5fo.esm.js.map +1 -0
  24. package/dist/index.browser-zfGYm0ST.esm.js +6060 -0
  25. package/dist/index.browser-zfGYm0ST.esm.js.map +1 -0
  26. package/dist/index.esm.js +1 -1
  27. package/dist/index.js +1 -1
  28. package/dist/{index.native-Dkf8NZ2O.js → index.native-BGaUOX9f.js} +61 -42
  29. package/dist/index.native-BGaUOX9f.js.map +1 -0
  30. package/dist/{index.native-CyEwEeKr.esm.js → index.native-BPQqeP6_.esm.js} +62 -43
  31. package/dist/index.native-BPQqeP6_.esm.js.map +1 -0
  32. package/dist/index.native.esm.js +1 -1
  33. package/dist/index.native.js +1 -1
  34. package/dist/{phantom-wallet-provider-fkcFbwPk.esm.js → phantom-wallet-provider-DheGhOp4.esm.js} +37 -6
  35. package/dist/phantom-wallet-provider-DheGhOp4.esm.js.map +1 -0
  36. package/dist/{phantom-wallet-provider-CVyVJmH0.js → phantom-wallet-provider-MFcwrRpJ.js} +37 -6
  37. package/dist/phantom-wallet-provider-MFcwrRpJ.js.map +1 -0
  38. package/dist/{privy-wallet-provider-CrBZ52nR.js → privy-wallet-provider-CFw6o7O5.js} +3 -3
  39. package/dist/privy-wallet-provider-CFw6o7O5.js.map +1 -0
  40. package/dist/{privy-wallet-provider-CpHAxPcv.esm.js → privy-wallet-provider-D15Au3j8.esm.js} +3 -3
  41. package/dist/privy-wallet-provider-D15Au3j8.esm.js.map +1 -0
  42. package/dist/solana-mobile-wallet-provider-BM9wdF0m.js +719 -0
  43. package/dist/solana-mobile-wallet-provider-BM9wdF0m.js.map +1 -0
  44. package/dist/solana-mobile-wallet-provider-ChHh-U_p.esm.js +698 -0
  45. package/dist/solana-mobile-wallet-provider-ChHh-U_p.esm.js.map +1 -0
  46. package/package.json +3 -2
  47. package/dist/index-B7yaLhND.esm.js.map +0 -1
  48. package/dist/index-BxXQhFLQ.js.map +0 -1
  49. package/dist/index-CP_wLmYu.esm.js.map +0 -1
  50. package/dist/index-CpaP1yGp.esm.js.map +0 -1
  51. package/dist/index-DP0xF34Z.js.map +0 -1
  52. package/dist/index-DQWyH96R.js.map +0 -1
  53. package/dist/index-DfOd8wW4.esm.js +0 -6
  54. package/dist/index-DfOd8wW4.esm.js.map +0 -1
  55. package/dist/index-FviRSm3S.js.map +0 -1
  56. package/dist/index.browser-1_M66nQ6.esm.js +0 -1096
  57. package/dist/index.browser-1_M66nQ6.esm.js.map +0 -1
  58. package/dist/index.browser-B_wQp2A8.esm.js.map +0 -1
  59. package/dist/index.browser-BfnOoa_h.js +0 -1099
  60. package/dist/index.browser-BfnOoa_h.js.map +0 -1
  61. package/dist/index.browser-BhppfDyf.js +0 -105
  62. package/dist/index.browser-BhppfDyf.js.map +0 -1
  63. package/dist/index.browser-OvGNsMPu.esm.js +0 -1002
  64. package/dist/index.browser-OvGNsMPu.esm.js.map +0 -1
  65. package/dist/index.browser-_zN3Uapq.js.map +0 -1
  66. package/dist/index.browser-vUinl_9y.esm.js +0 -102
  67. package/dist/index.browser-vUinl_9y.esm.js.map +0 -1
  68. package/dist/index.browser-vuTr40so.js +0 -1008
  69. package/dist/index.browser-vuTr40so.js.map +0 -1
  70. package/dist/index.native-CyEwEeKr.esm.js.map +0 -1
  71. package/dist/index.native-Dkf8NZ2O.js.map +0 -1
  72. package/dist/phantom-wallet-provider-CVyVJmH0.js.map +0 -1
  73. package/dist/phantom-wallet-provider-fkcFbwPk.esm.js.map +0 -1
  74. package/dist/privy-wallet-provider-CpHAxPcv.esm.js.map +0 -1
  75. package/dist/privy-wallet-provider-CrBZ52nR.js.map +0 -1
  76. package/dist/solana-mobile-wallet-provider-CAaGfPZJ.js +0 -579
  77. package/dist/solana-mobile-wallet-provider-CAaGfPZJ.js.map +0 -1
  78. package/dist/solana-mobile-wallet-provider-DGyWHJVI.esm.js +0 -558
  79. package/dist/solana-mobile-wallet-provider-DGyWHJVI.esm.js.map +0 -1
@@ -22,21 +22,6 @@ function _interopNamespaceDefault(e) {
22
22
  return Object.freeze(n);
23
23
  }
24
24
 
25
- function _mergeNamespaces(n, m) {
26
- m.forEach(function (e) {
27
- e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
28
- if (k !== 'default' && !(k in n)) {
29
- var d = Object.getOwnPropertyDescriptor(e, k);
30
- Object.defineProperty(n, k, d.get ? d : {
31
- enumerable: true,
32
- get: function () { return e[k]; }
33
- });
34
- }
35
- });
36
- });
37
- return Object.freeze(n);
38
- }
39
-
40
25
  var anchor__namespace = /*#__PURE__*/_interopNamespaceDefault(anchor);
41
26
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React$2);
42
27
 
@@ -6785,6 +6770,28 @@ class WebSessionManager {
6785
6770
  static async storeSession(address, accessToken, idToken, refreshToken) {
6786
6771
  if (typeof window === "undefined")
6787
6772
  return;
6773
+ // JWT-wallet binding: refuse to store a session whose idToken is bound
6774
+ // to a different wallet than `address`. Prevents races that would otherwise
6775
+ // leave localStorage with mismatched address/token state.
6776
+ try {
6777
+ const payloadB64 = idToken.split(".")[1];
6778
+ if (payloadB64) {
6779
+ const payload = JSON.parse(this.decodeBase64Url(payloadB64));
6780
+ const tokenWallet = payload["custom:walletAddress"];
6781
+ if (tokenWallet && tokenWallet !== address) {
6782
+ throw new Error(`[WebSessionManager] Refusing to store session: address (${address}) does not match idToken custom:walletAddress (${tokenWallet})`);
6783
+ }
6784
+ if (!tokenWallet) {
6785
+ console.warn("[WebSessionManager] storeSession: idToken has no custom:walletAddress claim — writing without validation");
6786
+ }
6787
+ }
6788
+ }
6789
+ catch (err) {
6790
+ if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
6791
+ throw err;
6792
+ }
6793
+ console.warn("[WebSessionManager] storeSession: failed to decode idToken for validation:", err);
6794
+ }
6788
6795
  const config = await getConfig();
6789
6796
  const currentAppId = config.appId;
6790
6797
  localStorage.setItem(this.TAROBASE_SESSION_STORAGE_KEY, JSON.stringify({
@@ -9483,11 +9490,11 @@ function requireSrc$1 () {
9483
9490
  }
9484
9491
 
9485
9492
  var bs58$1;
9486
- var hasRequiredBs58$1;
9493
+ var hasRequiredBs58;
9487
9494
 
9488
- function requireBs58$1 () {
9489
- if (hasRequiredBs58$1) return bs58$1;
9490
- hasRequiredBs58$1 = 1;
9495
+ function requireBs58 () {
9496
+ if (hasRequiredBs58) return bs58$1;
9497
+ hasRequiredBs58 = 1;
9491
9498
  var basex = requireSrc$1();
9492
9499
  var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
9493
9500
 
@@ -9495,8 +9502,8 @@ function requireBs58$1 () {
9495
9502
  return bs58$1;
9496
9503
  }
9497
9504
 
9498
- var bs58Exports$1 = requireBs58$1();
9499
- var bs58$2 = /*@__PURE__*/getDefaultExportFromCjs(bs58Exports$1);
9505
+ var bs58Exports = requireBs58();
9506
+ var bs58 = /*@__PURE__*/getDefaultExportFromCjs(bs58Exports);
9500
9507
 
9501
9508
  // ─────────────────────────────────────────────────────────────
9502
9509
  // Local implementation of getSimulationComputeUnits
@@ -9758,7 +9765,7 @@ function loadKeypairFromEnv() {
9758
9765
  try {
9759
9766
  const secretKey = secret.trim().startsWith("[")
9760
9767
  ? Uint8Array.from(JSON.parse(secret))
9761
- : bs58$2.decode(secret.trim());
9768
+ : bs58.decode(secret.trim());
9762
9769
  return web3_js.Keypair.fromSecretKey(secretKey);
9763
9770
  }
9764
9771
  catch (err) {
@@ -11703,6 +11710,28 @@ class ReactNativeSessionManager {
11703
11710
  /* STORE */
11704
11711
  /* ------------------------------------------------------------------ */
11705
11712
  static async storeSession(address, accessToken, idToken, refreshToken) {
11713
+ // JWT-wallet binding: refuse to store a session whose idToken is bound
11714
+ // to a different wallet than `address`. Prevents races that would otherwise
11715
+ // leave storage with mismatched address/token state.
11716
+ try {
11717
+ const payloadB64 = idToken.split(".")[1];
11718
+ if (payloadB64) {
11719
+ const payload = JSON.parse(this.decodeBase64Url(payloadB64));
11720
+ const tokenWallet = payload["custom:walletAddress"];
11721
+ if (tokenWallet && tokenWallet !== address) {
11722
+ throw new Error(`[ReactNativeSessionManager] Refusing to store session: address (${address}) does not match idToken custom:walletAddress (${tokenWallet})`);
11723
+ }
11724
+ if (!tokenWallet) {
11725
+ console.warn("[ReactNativeSessionManager] storeSession: idToken has no custom:walletAddress claim — writing without validation");
11726
+ }
11727
+ }
11728
+ }
11729
+ catch (err) {
11730
+ if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
11731
+ throw err;
11732
+ }
11733
+ console.warn("[ReactNativeSessionManager] storeSession: failed to decode idToken for validation:", err);
11734
+ }
11706
11735
  const config = await getConfig();
11707
11736
  const currentAppId = config.appId;
11708
11737
  this.getStorage().setItem(this.TAROBASE_SESSION_STORAGE_KEY, JSON.stringify({
@@ -12809,10 +12838,10 @@ let currentAuthProvider = null;
12809
12838
  let currentAuthMethod = null;
12810
12839
  let initConfig = null;
12811
12840
  // --- localStorage helpers: track which auth method the user last logged in with ---
12812
- const STORED_AUTH_METHOD_KEY = 'tarobase_last_auth_method';
12841
+ const STORED_AUTH_METHOD_KEY$1 = 'tarobase_last_auth_method';
12813
12842
  function getStoredAuthMethod() {
12814
12843
  try {
12815
- return getPlatform().storage.getItem(STORED_AUTH_METHOD_KEY);
12844
+ return getPlatform().storage.getItem(STORED_AUTH_METHOD_KEY$1);
12816
12845
  }
12817
12846
  catch (_a) {
12818
12847
  return null;
@@ -12821,10 +12850,10 @@ function getStoredAuthMethod() {
12821
12850
  function setStoredAuthMethod(method) {
12822
12851
  try {
12823
12852
  if (method) {
12824
- getPlatform().storage.setItem(STORED_AUTH_METHOD_KEY, method);
12853
+ getPlatform().storage.setItem(STORED_AUTH_METHOD_KEY$1, method);
12825
12854
  }
12826
12855
  else {
12827
- getPlatform().storage.removeItem(STORED_AUTH_METHOD_KEY);
12856
+ getPlatform().storage.removeItem(STORED_AUTH_METHOD_KEY$1);
12828
12857
  }
12829
12858
  }
12830
12859
  catch (_a) {
@@ -15701,7 +15730,7 @@ async function loadDependencies() {
15701
15730
  const [reactModule, reactDomModule, phantomModule] = await Promise.all([
15702
15731
  import('react'),
15703
15732
  import('react-dom/client'),
15704
- Promise.resolve().then(function () { return require('./index-FviRSm3S.js'); })
15733
+ Promise.resolve().then(function () { return require('./index-BoWQVxMI.js'); })
15705
15734
  ]);
15706
15735
  // Extract default export from ESM module namespace
15707
15736
  // Dynamic import() returns { default: Module, ...exports }, not the module directly
@@ -15847,6 +15876,17 @@ class PhantomWalletProvider {
15847
15876
  const isMobile = detectMobile();
15848
15877
  const hasPhantomInjected = discoveredWallets.some((w) => w.id === 'phantom');
15849
15878
  const showDeeplink = isMobile && sdkProviders.includes('deeplink') && !hasPhantomInjected;
15879
+ // Treat MWA's own wallet-standard registrations as not-injected, so the MWA
15880
+ // button still appears when only MWA is present (e.g. Android Chrome on Seeker).
15881
+ const hasInjectedWallet = discoveredWallets.some((w) => {
15882
+ var _a, _b;
15883
+ const id = String((_a = w.id) !== null && _a !== void 0 ? _a : '').toLowerCase();
15884
+ const name = String((_b = w.name) !== null && _b !== void 0 ? _b : '').toLowerCase();
15885
+ return (id !== 'mobile-wallet-adapter' &&
15886
+ id !== 'remote-mobile-wallet-adapter' &&
15887
+ name !== 'mobile wallet adapter' &&
15888
+ name !== 'remote mobile wallet adapter');
15889
+ });
15850
15890
  // Track previous modal state to detect closes
15851
15891
  const prevModalOpen = React$1.useRef(false);
15852
15892
  // Track when modal was closed because user selected a wallet (not dismissed)
@@ -15895,6 +15935,16 @@ class PhantomWalletProvider {
15895
15935
  if (!(phantom === null || phantom === void 0 ? void 0 : phantom.isConnected) || (phantom === null || phantom === void 0 ? void 0 : phantom.isLoading) || that.loginInProgress || that.autoLoginInProgress || that.pendingLogin) {
15896
15936
  return;
15897
15937
  }
15938
+ // Don't clobber a session owned by MWA on Seeker. MWA marks the
15939
+ // auth method as soon as login starts (see solana-mobile-wallet-provider),
15940
+ // and clears it on logout, so this guard is correct in both
15941
+ // steady-state and post-logout cases.
15942
+ try {
15943
+ if (getPlatform().storage.getItem('tarobase_last_auth_method') === 'mobile-wallet-adapter') {
15944
+ return;
15945
+ }
15946
+ }
15947
+ catch (_b) { }
15898
15948
  // Need solana to be available AND connected for signing
15899
15949
  if (!solana || !solanaHook.isAvailable || !solana.connected) {
15900
15950
  return;
@@ -15924,12 +15974,21 @@ class PhantomWalletProvider {
15924
15974
  const signatureBytes = signResult.signature;
15925
15975
  const signature = bufferExports.Buffer.from(signatureBytes).toString('base64');
15926
15976
  const createSessionResult = await createSessionWithSignature(publicKey, messageText, signature);
15977
+ // Pre-write guard: MWA may have started a login while we were
15978
+ // in flight. If MWA owns the auth method now, abort before we
15979
+ // overwrite its session (or its in-flight session).
15980
+ try {
15981
+ if (getPlatform().storage.getItem('tarobase_last_auth_method') === 'mobile-wallet-adapter') {
15982
+ return;
15983
+ }
15984
+ }
15985
+ catch (_c) { }
15927
15986
  await WebSessionManager.storeSession(publicKey, createSessionResult.accessToken, createSessionResult.idToken, createSessionResult.refreshToken);
15928
15987
  // Mark auth method so clearIncompatibleSession() doesn't wipe this session
15929
15988
  try {
15930
15989
  getPlatform().storage.setItem('tarobase_last_auth_method', 'phantom');
15931
15990
  }
15932
- catch (_b) { }
15991
+ catch (_d) { }
15933
15992
  setCurrentUser({ provider: that, address: publicKey });
15934
15993
  }
15935
15994
  catch (error) {
@@ -16285,8 +16344,9 @@ class PhantomWalletProvider {
16285
16344
  }), 'Open Phantom app'));
16286
16345
  }
16287
16346
  // Mobile Wallet Adapter button — shown on Android when MWA callback is available
16347
+ // and no injected wallet is present (hides button inside Phantom/Solflare/etc. in-app browsers).
16288
16348
  const isAndroid = detectAndroid();
16289
- if (isAndroid && that.onSwitchToMWA) {
16349
+ if (isAndroid && that.onSwitchToMWA && !hasInjectedWallet) {
16290
16350
  walletButtons.push(React$1.createElement('button', {
16291
16351
  key: 'mobile-wallet',
16292
16352
  style: buttonStyle('mobile-wallet'),
@@ -20328,26 +20388,16 @@ function requireSrc () {
20328
20388
  return src;
20329
20389
  }
20330
20390
 
20331
- var bs58;
20332
- var hasRequiredBs58;
20391
+ var srcExports = requireSrc();
20392
+ var basex = /*@__PURE__*/getDefaultExportFromCjs$1(srcExports);
20333
20393
 
20334
- function requireBs58 () {
20335
- if (hasRequiredBs58) return bs58;
20336
- hasRequiredBs58 = 1;
20337
- var basex = requireSrc();
20338
- var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
20394
+ var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
20395
+ var base58 = basex(ALPHABET);
20339
20396
 
20340
- bs58 = basex(ALPHABET);
20341
- return bs58;
20342
- }
20343
-
20344
- var bs58Exports = requireBs58();
20345
- var base58 = /*@__PURE__*/getDefaultExportFromCjs$1(bs58Exports);
20346
-
20347
- var index = /*#__PURE__*/_mergeNamespaces({
20397
+ var index = /*#__PURE__*/Object.freeze({
20348
20398
  __proto__: null,
20349
20399
  default: base58
20350
- }, [bs58Exports]);
20400
+ });
20351
20401
 
20352
20402
  const SURFNET_RPC_URL$1 = "https://surfpool.fly.dev";
20353
20403
  let React;
@@ -21249,26 +21299,135 @@ function isMobileWalletAvailable() {
21249
21299
  return detectAndroid();
21250
21300
  }
21251
21301
  const ED25519_SIGNATURE_LENGTH = 64;
21252
- // Dynamically imported MWA protocol module
21253
- let mwaProtocolModule = null;
21254
- let mwaProtocolLoadPromise = null;
21255
- async function loadMwaProtocol() {
21256
- if (mwaProtocolModule)
21257
- return;
21258
- if (typeof window === 'undefined')
21259
- return;
21260
- if (mwaProtocolLoadPromise)
21261
- return mwaProtocolLoadPromise;
21262
- mwaProtocolLoadPromise = (async () => {
21263
- try {
21264
- mwaProtocolModule = await Promise.resolve().then(function () { return require('./index.browser-BhppfDyf.js'); });
21302
+ const STORED_AUTH_METHOD_KEY = 'tarobase_last_auth_method';
21303
+ const MWA_AUTH_METHOD = 'mobile-wallet-adapter';
21304
+ /**
21305
+ * Normalize a chain string to a wallet-standard Solana chain identifier.
21306
+ *
21307
+ * Handles three input shapes that all show up in practice:
21308
+ * - Bare cluster name from `SolanaMobileWalletConfig.cluster` (e.g. 'devnet').
21309
+ * - Prefixed `solana:cluster` (e.g. 'solana:devnet').
21310
+ * - Double-prefixed `solana:solana:cluster` (constructor used to wrap cluster
21311
+ * with `solana:` blindly; if a caller already passed a prefixed string the
21312
+ * result was `solana:solana:devnet`).
21313
+ *
21314
+ * Wallet-standard Solana chains are exactly:
21315
+ * 'solana:mainnet' | 'solana:devnet' | 'solana:testnet' | 'solana:localnet'
21316
+ * — `mainnet-beta` is NOT a valid wallet-standard identifier and must be
21317
+ * normalized to `solana:mainnet`.
21318
+ */
21319
+ function mapChainToWalletStandard(input) {
21320
+ if (!input)
21321
+ return 'solana:mainnet';
21322
+ let s = String(input).toLowerCase();
21323
+ while (s.startsWith('solana:'))
21324
+ s = s.slice('solana:'.length);
21325
+ if (s === 'mainnet-beta' || s === 'mainnet')
21326
+ return 'solana:mainnet';
21327
+ if (s === 'devnet')
21328
+ return 'solana:devnet';
21329
+ if (s === 'testnet')
21330
+ return 'solana:testnet';
21331
+ if (s === 'localnet')
21332
+ return 'solana:localnet';
21333
+ return 'solana:mainnet';
21334
+ }
21335
+ /**
21336
+ * Serialize a Transaction/VersionedTransaction to a Uint8Array wire payload
21337
+ * that the wallet-standard `solana:signTransaction` /
21338
+ * `solana:signAndSendTransaction` features expect.
21339
+ *
21340
+ * Legacy transactions must serialize with `requireAllSignatures: false` and
21341
+ * `verifySignatures: false` — the wallet hasn't signed yet, and the default
21342
+ * `serialize()` would throw "Signature verification failed". Versioned
21343
+ * transactions use the default `serialize()` which already permits unsigned
21344
+ * payloads. Mirrors the helper at
21345
+ * `@solana-mobile/mobile-wallet-adapter-protocol-web3js/lib/esm/index.browser.js:13-18`.
21346
+ */
21347
+ function txToWireBytes(tx) {
21348
+ if ('version' in tx)
21349
+ return tx.serialize();
21350
+ return tx.serialize({ requireAllSignatures: false, verifySignatures: false });
21351
+ }
21352
+ /**
21353
+ * Deserialize a wire-format transaction returned by the wallet
21354
+ * `solana:signTransaction` feature. Mirrors the helper at
21355
+ * `@solana-mobile/mobile-wallet-adapter-protocol-web3js/lib/esm/index.browser.js:19-23`
21356
+ * so legacy and versioned bytes both round-trip correctly.
21357
+ */
21358
+ function txFromWireBytes(byteArray) {
21359
+ const messageOffset = byteArray[0] * ED25519_SIGNATURE_LENGTH + 1;
21360
+ const messageVersion = web3_js.VersionedMessage.deserializeMessageVersion(byteArray.slice(messageOffset, byteArray.length));
21361
+ if (messageVersion === 'legacy') {
21362
+ return web3_js.Transaction.from(byteArray);
21363
+ }
21364
+ return web3_js.VersionedTransaction.deserialize(byteArray);
21365
+ }
21366
+ /**
21367
+ * Per-method runtime narrowing of wallet-standard features. The wallet's
21368
+ * `.features` type is a union (`signAndSendTransaction` | `signTransaction`),
21369
+ * and after authorization the wallet may also narrow `#optionalFeatures`
21370
+ * based on actual wallet capabilities. Narrow at the call site so a method
21371
+ * that needs only `signMessage` doesn't fail when a wallet lacks
21372
+ * `signTransaction`.
21373
+ */
21374
+ function getSignMessageFeature(wallet) {
21375
+ const f = wallet.features;
21376
+ const feat = f['solana:signMessage'];
21377
+ if (!feat || typeof feat.signMessage !== 'function') {
21378
+ throw new Error('Wallet does not support solana:signMessage');
21379
+ }
21380
+ return feat;
21381
+ }
21382
+ function getSignTransactionFeature(wallet) {
21383
+ const f = wallet.features;
21384
+ const feat = f['solana:signTransaction'];
21385
+ if (!feat || typeof feat.signTransaction !== 'function') {
21386
+ throw new Error('Wallet does not support solana:signTransaction');
21387
+ }
21388
+ return feat;
21389
+ }
21390
+ function getSignAndSendTransactionFeature(wallet) {
21391
+ const f = wallet.features;
21392
+ const feat = f['solana:signAndSendTransaction'];
21393
+ if (!feat || typeof feat.signAndSendTransaction !== 'function') {
21394
+ throw new Error('Wallet does not support solana:signAndSendTransaction');
21395
+ }
21396
+ return feat;
21397
+ }
21398
+ function getConnectFeature(wallet) {
21399
+ const f = wallet.features;
21400
+ const feat = f['standard:connect'];
21401
+ if (!feat || typeof feat.connect !== 'function') {
21402
+ throw new Error('Wallet does not support standard:connect');
21403
+ }
21404
+ return feat;
21405
+ }
21406
+ function getDisconnectFeature(wallet) {
21407
+ const f = wallet.features;
21408
+ const feat = f['standard:disconnect'];
21409
+ return feat && typeof feat.disconnect === 'function' ? feat : null;
21410
+ }
21411
+ function writeAuthMethod(method) {
21412
+ try {
21413
+ if (method === null) {
21414
+ getPlatform().storage.removeItem(STORED_AUTH_METHOD_KEY);
21265
21415
  }
21266
- catch (e) {
21267
- console.warn('[SolanaMobileWallet] @solana-mobile/mobile-wallet-adapter-protocol-web3js not installed. Install it to enable Seeker wallet support.');
21268
- throw new Error('Missing @solana-mobile/mobile-wallet-adapter-protocol-web3js dependency');
21416
+ else {
21417
+ getPlatform().storage.setItem(STORED_AUTH_METHOD_KEY, method);
21269
21418
  }
21270
- })();
21271
- return mwaProtocolLoadPromise;
21419
+ }
21420
+ catch (_a) {
21421
+ // storage may be unavailable
21422
+ }
21423
+ }
21424
+ function readAuthMethod() {
21425
+ try {
21426
+ return getPlatform().storage.getItem(STORED_AUTH_METHOD_KEY);
21427
+ }
21428
+ catch (_a) {
21429
+ return null;
21430
+ }
21272
21431
  }
21273
21432
  /**
21274
21433
  * Registers Mobile Wallet Adapter as a wallet-standard wallet so it appears
@@ -21283,7 +21442,7 @@ async function registerMobileWalletAdapter(config) {
21283
21442
  if (typeof window === 'undefined')
21284
21443
  return;
21285
21444
  try {
21286
- const walletStandardMobile = await Promise.resolve().then(function () { return require('./index.browser-_zN3Uapq.js'); });
21445
+ const walletStandardMobile = await Promise.resolve().then(function () { return require('./index.browser-DZCNegue.js'); });
21287
21446
  const registerMwa = walletStandardMobile.registerMwa || ((_a = walletStandardMobile.default) === null || _a === void 0 ? void 0 : _a.registerMwa);
21288
21447
  if (!registerMwa) {
21289
21448
  console.warn('[SolanaMobileWallet] registerMwa not found in @solana-mobile/wallet-standard-mobile');
@@ -21312,32 +21471,41 @@ async function registerMobileWalletAdapter(config) {
21312
21471
  registerMwa(options);
21313
21472
  }
21314
21473
  catch (e) {
21315
- // @solana-mobile/wallet-standard-mobile is an optional dependency
21316
- // Silently skip if not installed — the provider still works via
21317
- // @solana-mobile/mobile-wallet-adapter-protocol-web3js directly
21318
21474
  console.debug('[SolanaMobileWallet] @solana-mobile/wallet-standard-mobile not available, skipping wallet-standard registration');
21319
21475
  }
21320
21476
  }
21321
21477
  /**
21322
- * SolanaMobileWalletProvider implements the AuthProvider interface using the
21323
- * Solana Mobile Wallet Adapter (MWA) protocol's low-level `transact` API.
21478
+ * SolanaMobileWalletProvider implements the AuthProvider interface using
21479
+ * Solana Mobile's wallet-standard wrapper (`LocalSolanaMobileWalletAdapterWallet`).
21480
+ *
21481
+ * Why wallet-standard and not the raw MWA protocol: as of
21482
+ * `@solana-mobile/wallet-standard-mobile@0.5.0+`, the wallet's internal
21483
+ * `#transact` calls `checkLocalNetworkAccessPermission()` before opening the
21484
+ * localhost WebSocket. That helper renders a three-stage UX flow Solana
21485
+ * Mobile designed specifically to defuse Chrome's Local Network Access
21486
+ * permission dialog (which renders with disabled buttons on Android Chrome,
21487
+ * the source of the long-running Seeker MWA bug):
21488
+ *
21489
+ * 1. "Allow connections to your wallet" informational modal.
21490
+ * 2. Chrome's permission prompt (interactive because it's spawned as a
21491
+ * fresh user gesture from step 1).
21492
+ * 3. "Ready to connect!" success modal.
21324
21493
  *
21325
- * This enables TaroBase dApps to work with any MWA-compliant wallet on Solana
21326
- * mobile devices (Seeker, Saga) including the native Seed Vault Wallet,
21327
- * Phantom, Solflare, and any other wallet that implements the MWA protocol.
21494
+ * `checkLocalNetworkAccessPermission` is internal to the library it's not
21495
+ * exported. The only way to invoke it is to go through the wallet's
21496
+ * `standard:connect` / `solana:sign*` features, which is what this provider
21497
+ * does.
21328
21498
  *
21329
- * By using `transact()` directly (instead of the wallet-adapter wrapper),
21330
- * login combines authorize + signMessage into a single wallet session —
21331
- * meaning one popup/approval instead of two.
21499
+ * Notes on UX: login uses two wallet popups in succession — `standard:connect`
21500
+ * (authorize) and `solana:signMessage` (sign the Tarobase nonce). The
21501
+ * previous implementation combined both inside a single `transact` callback;
21502
+ * splitting them is the cost of going through wallet-standard, and is
21503
+ * acceptable given the alternative was broken on Seeker.
21332
21504
  */
21333
21505
  class SolanaMobileWalletProvider {
21334
21506
  constructor(networkUrl = null, config = {}) {
21335
- // MWA authorization state
21336
- this.authToken = null;
21337
- this.walletUriBase = null;
21338
- this.base64Address = null;
21339
- this.authorizedPublicKey = null;
21340
- this.publicKeyObj = null;
21507
+ /** LocalSolanaMobileWalletAdapterWallet, lazy-constructed in ensureWallet(). */
21508
+ this.wallet = null;
21341
21509
  this.networkUrl = networkUrl;
21342
21510
  this.config = config;
21343
21511
  if (typeof window === 'undefined') {
@@ -21350,7 +21518,7 @@ class SolanaMobileWalletProvider {
21350
21518
  name: 'TaroBase App',
21351
21519
  uri: getPlatform().getLocationOrigin(),
21352
21520
  };
21353
- this.chain = `solana:${config.cluster || 'mainnet-beta'}`;
21521
+ this.cluster = config.cluster || 'mainnet-beta';
21354
21522
  SolanaMobileWalletProvider.instance = this;
21355
21523
  }
21356
21524
  static getInstance(networkUrl, config) {
@@ -21359,131 +21527,118 @@ class SolanaMobileWalletProvider {
21359
21527
  }
21360
21528
  return SolanaMobileWalletProvider.instance;
21361
21529
  }
21362
- /** Config for transact() routes to the same wallet if we've already authorized */
21363
- getAssociationConfig() {
21364
- if (this.walletUriBase) {
21365
- return { baseUri: this.walletUriBase };
21366
- }
21367
- return undefined;
21530
+ /** Lazy-construct LocalSolanaMobileWalletAdapterWallet on first need. */
21531
+ async ensureWallet() {
21532
+ if (this.wallet)
21533
+ return this.wallet;
21534
+ const mod = await Promise.resolve().then(function () { return require('./index.browser-DZCNegue.js'); });
21535
+ const chain = mapChainToWalletStandard(this.cluster);
21536
+ this.wallet = new mod.LocalSolanaMobileWalletAdapterWallet({
21537
+ appIdentity: this.appIdentity,
21538
+ authorizationCache: mod.createDefaultAuthorizationCache(),
21539
+ chains: [chain],
21540
+ chainSelector: mod.createDefaultChainSelector(),
21541
+ onWalletNotFound: mod.createDefaultWalletNotFoundHandler(),
21542
+ });
21543
+ return this.wallet;
21368
21544
  }
21369
- /** Reauthorize within a transact callback using a stored auth_token */
21370
- async reauthorizeWallet(wallet) {
21371
- if (!this.authToken) {
21372
- // No existing auth do a fresh authorize
21373
- const authResult = await wallet.authorize({
21374
- identity: this.appIdentity,
21375
- chain: this.chain,
21376
- });
21377
- this.storeAuthResult(authResult);
21378
- return authResult;
21545
+ /**
21546
+ * Ensure the wallet has an active authorization. After a Tarobase session
21547
+ * is restored from storage on cold-start, `wallet.accounts` is empty until
21548
+ * we silently reconnect from the AuthorizationCache. If the cache is also
21549
+ * empty, fall back to interactive `login()` (which surfaces the three-stage
21550
+ * Solana Mobile LNA flow + wallet popups).
21551
+ *
21552
+ * Returns the wallet-standard `WalletAccount` to use for sign operations.
21553
+ */
21554
+ async ensureAuthorized() {
21555
+ const wallet = await this.ensureWallet();
21556
+ if (wallet.accounts.length === 0) {
21557
+ try {
21558
+ const connectFeat = getConnectFeature(wallet);
21559
+ await connectFeat.connect({ silent: true });
21560
+ }
21561
+ catch (e) {
21562
+ console.warn('[SolanaMobileWallet] silent connect failed:', e === null || e === void 0 ? void 0 : e.message);
21563
+ }
21379
21564
  }
21380
- try {
21381
- const authResult = await wallet.reauthorize({
21382
- auth_token: this.authToken,
21383
- identity: this.appIdentity,
21384
- });
21385
- this.storeAuthResult(authResult);
21386
- return authResult;
21387
- }
21388
- catch (e) {
21389
- // Reauth failed (token expired, wallet reset, etc.) — try fresh authorize
21390
- console.warn('[SolanaMobileWallet] Reauthorization failed, attempting fresh authorize:', e === null || e === void 0 ? void 0 : e.message);
21391
- const authResult = await wallet.authorize({
21392
- identity: this.appIdentity,
21393
- chain: this.chain,
21394
- });
21395
- this.storeAuthResult(authResult);
21396
- return authResult;
21565
+ if (wallet.accounts.length === 0) {
21566
+ const user = await this.login();
21567
+ if (!user)
21568
+ throw new Error('MWA not connected');
21397
21569
  }
21570
+ return wallet.accounts[0];
21398
21571
  }
21399
- /** Persist auth result from an authorize/reauthorize call */
21400
- storeAuthResult(authResult) {
21401
- var _a;
21402
- this.authToken = authResult.auth_token;
21403
- this.walletUriBase = authResult.wallet_uri_base;
21404
- if (((_a = authResult.accounts) === null || _a === void 0 ? void 0 : _a.length) > 0) {
21405
- const account = authResult.accounts[0];
21406
- this.base64Address = account.address;
21407
- // Decode base64 address → PublicKey → base58
21408
- const addressBytes = Uint8Array.from(getPlatform().atob(account.address), c => c.charCodeAt(0));
21409
- this.publicKeyObj = new web3_js.PublicKey(addressBytes);
21410
- this.authorizedPublicKey = this.publicKeyObj.toBase58();
21411
- }
21572
+ /** Returns the active wallet-standard chain identifier (e.g. 'solana:mainnet'). */
21573
+ getChain() {
21574
+ return mapChainToWalletStandard(this.cluster);
21412
21575
  }
21413
21576
  async login() {
21414
21577
  var _a, _b, _c, _d, _e;
21415
21578
  setAuthLoading(true);
21579
+ // Mark the auth method early so a concurrent Phantom auto-create-session
21580
+ // effect (see phantom-wallet-provider) sees 'mobile-wallet-adapter'
21581
+ // during our slow connect/sign roundtrip and backs off. Capture the
21582
+ // previous value so we can restore it if login fails.
21583
+ const prevAuthMethod = readAuthMethod();
21584
+ writeAuthMethod(MWA_AUTH_METHOD);
21416
21585
  try {
21417
- await loadMwaProtocol();
21418
- const { transact } = mwaProtocolModule;
21419
- // Quick check: if we already have auth state and a valid session, skip
21420
- if (this.authorizedPublicKey) {
21586
+ const wallet = await this.ensureWallet();
21587
+ // Quick-check: wallet may already have authorization (e.g. from a
21588
+ // previous in-page login) and a matching Tarobase session skip
21589
+ // popups in that case.
21590
+ if (wallet.accounts.length > 0) {
21591
+ const accountPubkey = new web3_js.PublicKey(wallet.accounts[0].publicKey);
21592
+ const base58Addr = accountPubkey.toBase58();
21421
21593
  const existingSession = await WebSessionManager.getSession();
21422
- if (existingSession && existingSession.address === this.authorizedPublicKey) {
21423
- const user = { provider: this, address: this.authorizedPublicKey };
21594
+ if (existingSession && existingSession.address === base58Addr) {
21595
+ const user = { provider: this, address: base58Addr };
21424
21596
  setCurrentUser(user);
21425
21597
  return user;
21426
21598
  }
21427
21599
  }
21428
- // Pre-fetch nonce from server while wallet is not yet connected
21600
+ // Pre-fetch nonce while the wallet popup is not yet open.
21429
21601
  const nonce = await genAuthNonce();
21430
- // Single transact() call: authorize + signMessages one wallet popup
21431
- const result = await transact(async (wallet) => {
21432
- // Step 1: Authorize user approves the dApp
21433
- const authResult = await wallet.authorize({
21434
- identity: this.appIdentity,
21435
- chain: this.chain,
21436
- });
21437
- const base64Addr = authResult.accounts[0].address;
21438
- const addressBytes = Uint8Array.from(getPlatform().atob(base64Addr), c => c.charCodeAt(0));
21439
- const pubkey = new web3_js.PublicKey(addressBytes);
21440
- const base58Addr = pubkey.toBase58();
21441
- // Step 2: Sign the auth message — still in the same wallet session
21442
- const messageText = await genSolanaMessage(base58Addr, nonce);
21443
- const messageBytes = getPlatform().textEncode(messageText);
21444
- const signedMessages = await wallet.signMessages({
21445
- addresses: [base64Addr],
21446
- payloads: [messageBytes],
21447
- });
21448
- // The signed payload is [original message bytes][64-byte ed25519 signature]
21449
- const signedPayload = signedMessages[0];
21450
- const signatureBytes = signedPayload.slice(-ED25519_SIGNATURE_LENGTH);
21451
- return {
21452
- base58Address: base58Addr,
21453
- base64Address: base64Addr,
21454
- publicKey: pubkey,
21455
- signature: bufferExports.Buffer.from(signatureBytes).toString('base64'),
21456
- messageText,
21457
- authToken: authResult.auth_token,
21458
- walletUriBase: authResult.wallet_uri_base,
21459
- };
21460
- }, this.getAssociationConfig());
21461
- // Store MWA auth state for reauthorization in subsequent transact() calls
21462
- this.authToken = result.authToken;
21463
- this.walletUriBase = result.walletUriBase;
21464
- this.base64Address = result.base64Address;
21465
- this.authorizedPublicKey = result.base58Address;
21466
- this.publicKeyObj = result.publicKey;
21467
- // Check if we already have a valid session for this address
21602
+ // Wallet popup #1: standard:connect performs MWA authorize. This
21603
+ // is where wallet-standard's checkLocalNetworkAccessPermission()
21604
+ // fires the three-stage LNA UX (info modal → permission prompt →
21605
+ // success modal) before opening the localhost WebSocket.
21606
+ const connectFeat = getConnectFeature(wallet);
21607
+ const { accounts } = await connectFeat.connect();
21608
+ if (!accounts || accounts.length === 0) {
21609
+ throw new Error('MWA returned no accounts');
21610
+ }
21611
+ const account = accounts[0];
21612
+ const accountPubkey = new web3_js.PublicKey(account.publicKey);
21613
+ const base58Addr = accountPubkey.toBase58();
21614
+ // If we happen to already have a matching Tarobase session, reuse it.
21468
21615
  const existingSession = await WebSessionManager.getSession();
21469
- if (existingSession && existingSession.address === result.base58Address) {
21470
- const user = { provider: this, address: result.base58Address };
21616
+ if (existingSession && existingSession.address === base58Addr) {
21617
+ const user = { provider: this, address: base58Addr };
21471
21618
  setCurrentUser(user);
21472
21619
  return user;
21473
21620
  }
21474
- // Create new session on the server
21475
- const createSessionResult = await createSessionWithSignature(result.base58Address, result.messageText, result.signature);
21476
- await WebSessionManager.storeSession(result.base58Address, createSessionResult.accessToken, createSessionResult.idToken, createSessionResult.refreshToken);
21477
- // Mark auth method
21478
- try {
21479
- getPlatform().storage.setItem('tarobase_last_auth_method', 'mobile-wallet-adapter');
21621
+ // Wallet popup #2: sign the Tarobase nonce message.
21622
+ const messageText = await genSolanaMessage(base58Addr, nonce);
21623
+ const messageBytes = getPlatform().textEncode(messageText);
21624
+ const signMessageFeat = getSignMessageFeature(wallet);
21625
+ const signResults = await signMessageFeat.signMessage({ account, message: messageBytes });
21626
+ if (!signResults || signResults.length === 0) {
21627
+ throw new Error('MWA returned no signature');
21480
21628
  }
21481
- catch (_f) { }
21482
- const user = { provider: this, address: result.base58Address };
21629
+ const { signature: sigBytes } = signResults[0];
21630
+ const signatureBase64 = bufferExports.Buffer.from(sigBytes).toString('base64');
21631
+ // Create Tarobase session on the server.
21632
+ const createSessionResult = await createSessionWithSignature(base58Addr, messageText, signatureBase64);
21633
+ await WebSessionManager.storeSession(base58Addr, createSessionResult.accessToken, createSessionResult.idToken, createSessionResult.refreshToken);
21634
+ // Auth-method marker is already 'mobile-wallet-adapter' from above.
21635
+ const user = { provider: this, address: base58Addr };
21483
21636
  setCurrentUser(user);
21484
21637
  return user;
21485
21638
  }
21486
21639
  catch (error) {
21640
+ // Restore the previous auth-method marker since this login attempt failed.
21641
+ writeAuthMethod(prevAuthMethod);
21487
21642
  const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
21488
21643
  ((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes('user rejected')) ||
21489
21644
  ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes('user denied')) ||
@@ -21502,55 +21657,42 @@ class SolanaMobileWalletProvider {
21502
21657
  async restoreSession() {
21503
21658
  const session = await WebSessionManager.getSession();
21504
21659
  if (session) {
21505
- this.authorizedPublicKey = session.address;
21506
- this.publicKeyObj = new web3_js.PublicKey(session.address);
21507
21660
  return { provider: this, address: session.address };
21508
21661
  }
21509
21662
  return null;
21510
21663
  }
21511
21664
  async logout() {
21512
- // Deauthorize with the wallet if we have an auth_token
21513
- if (this.authToken) {
21514
- try {
21515
- await loadMwaProtocol();
21516
- const { transact } = mwaProtocolModule;
21517
- const authToken = this.authToken;
21518
- await transact(async (wallet) => {
21519
- await wallet.deauthorize({ auth_token: authToken });
21520
- }, this.getAssociationConfig());
21521
- }
21522
- catch (error) {
21523
- console.error('[SolanaMobileWallet] Deauthorize error:', error);
21665
+ try {
21666
+ const wallet = await this.ensureWallet();
21667
+ const disconnectFeat = getDisconnectFeature(wallet);
21668
+ if (disconnectFeat) {
21669
+ // Disconnect clears the AuthorizationCache and resets
21670
+ // wallet.#authorization internally (no LNA dialog).
21671
+ await disconnectFeat.disconnect();
21524
21672
  }
21525
21673
  }
21526
- this.authToken = null;
21527
- this.walletUriBase = null;
21528
- this.base64Address = null;
21529
- this.authorizedPublicKey = null;
21530
- this.publicKeyObj = null;
21674
+ catch (error) {
21675
+ console.error('[SolanaMobileWallet] Disconnect error:', error);
21676
+ }
21531
21677
  WebSessionManager.clearSession();
21678
+ // Clear the auth-method marker so Phantom auto-create is unblocked
21679
+ // for any subsequent fresh login on this device.
21680
+ writeAuthMethod(null);
21532
21681
  setCurrentUser(null);
21533
21682
  }
21534
21683
  async signMessage(message) {
21535
21684
  var _a, _b;
21536
- if (!this.authorizedPublicKey || !this.base64Address) {
21537
- throw new Error('Not connected. Call login() first.');
21538
- }
21539
- await loadMwaProtocol();
21540
- const { transact } = mwaProtocolModule;
21541
- const base64Addr = this.base64Address;
21685
+ const account = await this.ensureAuthorized();
21686
+ const wallet = await this.ensureWallet();
21542
21687
  try {
21543
- const signedMessages = await transact(async (wallet) => {
21544
- await this.reauthorizeWallet(wallet);
21545
- const messageBytes = getPlatform().textEncode(message);
21546
- return wallet.signMessages({
21547
- addresses: [base64Addr],
21548
- payloads: [messageBytes],
21549
- });
21550
- }, this.getAssociationConfig());
21551
- const signedPayload = signedMessages[0];
21552
- const signatureBytes = signedPayload.slice(-ED25519_SIGNATURE_LENGTH);
21553
- return bufferExports.Buffer.from(signatureBytes).toString('base64');
21688
+ const signMessageFeat = getSignMessageFeature(wallet);
21689
+ const messageBytes = getPlatform().textEncode(message);
21690
+ const results = await signMessageFeat.signMessage({ account, message: messageBytes });
21691
+ if (!results || results.length === 0) {
21692
+ throw new Error('MWA returned no signature');
21693
+ }
21694
+ const { signature: sigBytes } = results[0];
21695
+ return bufferExports.Buffer.from(sigBytes).toString('base64');
21554
21696
  }
21555
21697
  catch (error) {
21556
21698
  if (((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('not connected')) || ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('not authorized')) ||
@@ -21563,41 +21705,42 @@ class SolanaMobileWalletProvider {
21563
21705
  }
21564
21706
  async signTransaction(transaction) {
21565
21707
  var _a, _b;
21566
- if (!this.publicKeyObj) {
21567
- throw new Error('Not connected. Call login() first.');
21568
- }
21569
- await loadMwaProtocol();
21570
- const { transact } = mwaProtocolModule;
21571
- // Ensure blockhash and fee payer are set before signing
21708
+ const account = await this.ensureAuthorized();
21709
+ const connectedPubkey = new web3_js.PublicKey(account.publicKey);
21710
+ const wallet = await this.ensureWallet();
21711
+ const chain = this.getChain();
21712
+ // Preserve existing prep: fill missing blockhash / fee payer so call
21713
+ // sites that build a tx without these fields don't regress.
21572
21714
  const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
21573
21715
  if (isLegacyTransaction) {
21574
21716
  const legacyTx = transaction;
21575
21717
  if (!legacyTx.recentBlockhash) {
21576
- const rpcUrl = this.getRpcUrl();
21577
- const connection = new web3_js.Connection(rpcUrl, 'confirmed');
21578
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
21718
+ const conn = new web3_js.Connection(this.getRpcUrl(), 'confirmed');
21719
+ const { blockhash, lastValidBlockHeight } = await conn.getLatestBlockhash('confirmed');
21579
21720
  legacyTx.recentBlockhash = blockhash;
21580
21721
  legacyTx.lastValidBlockHeight = lastValidBlockHeight;
21581
21722
  }
21582
- if (!legacyTx.feePayer && this.publicKeyObj) {
21583
- legacyTx.feePayer = this.publicKeyObj;
21723
+ if (!legacyTx.feePayer) {
21724
+ legacyTx.feePayer = connectedPubkey;
21584
21725
  }
21585
21726
  }
21586
21727
  else {
21587
21728
  const versionedTx = transaction;
21588
21729
  if (!versionedTx.message.recentBlockhash) {
21589
- const rpcUrl = this.getRpcUrl();
21590
- const connection = new web3_js.Connection(rpcUrl, 'confirmed');
21591
- const { blockhash } = await connection.getLatestBlockhash('confirmed');
21730
+ const conn = new web3_js.Connection(this.getRpcUrl(), 'confirmed');
21731
+ const { blockhash } = await conn.getLatestBlockhash('confirmed');
21592
21732
  versionedTx.message.recentBlockhash = blockhash;
21593
21733
  }
21594
21734
  }
21595
21735
  try {
21596
- const signedTransactions = await transact(async (wallet) => {
21597
- await this.reauthorizeWallet(wallet);
21598
- return wallet.signTransactions({ transactions: [transaction] });
21599
- }, this.getAssociationConfig());
21600
- return signedTransactions[0];
21736
+ const signTxFeat = getSignTransactionFeature(wallet);
21737
+ const wireBytes = txToWireBytes(transaction);
21738
+ const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
21739
+ if (!results || results.length === 0) {
21740
+ throw new Error('MWA returned no signed transaction');
21741
+ }
21742
+ const { signedTransaction: signedBytes } = results[0];
21743
+ return txFromWireBytes(new Uint8Array(signedBytes));
21601
21744
  }
21602
21745
  catch (error) {
21603
21746
  if (((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('not connected')) || ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('not authorized')) ||
@@ -21610,15 +21753,15 @@ class SolanaMobileWalletProvider {
21610
21753
  }
21611
21754
  async signAndSubmitTransaction(transaction, feePayer) {
21612
21755
  var _a, _b, _c, _d, _e, _f;
21613
- if (!this.publicKeyObj) {
21614
- throw new Error('Not connected. Call login() first.');
21615
- }
21616
- await loadMwaProtocol();
21617
- const { transact } = mwaProtocolModule;
21756
+ const account = await this.ensureAuthorized();
21757
+ const connectedPubkey = new web3_js.PublicKey(account.publicKey);
21758
+ const wallet = await this.ensureWallet();
21759
+ const chain = this.getChain();
21618
21760
  const rpcUrl = this.getRpcUrl();
21619
21761
  const connection = new web3_js.Connection(rpcUrl, 'confirmed');
21620
21762
  const isSurfnet = rpcUrl === SURFNET_RPC_URL$2;
21621
21763
  try {
21764
+ // Preserve existing prep: refresh blockhash and set fee payer.
21622
21765
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
21623
21766
  const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
21624
21767
  if (isLegacyTransaction) {
@@ -21626,12 +21769,7 @@ class SolanaMobileWalletProvider {
21626
21769
  legacyTx.recentBlockhash = blockhash;
21627
21770
  legacyTx.lastValidBlockHeight = lastValidBlockHeight;
21628
21771
  if (!legacyTx.feePayer) {
21629
- if (feePayer) {
21630
- legacyTx.feePayer = feePayer;
21631
- }
21632
- else if (this.publicKeyObj) {
21633
- legacyTx.feePayer = this.publicKeyObj;
21634
- }
21772
+ legacyTx.feePayer = feePayer !== null && feePayer !== void 0 ? feePayer : connectedPubkey;
21635
21773
  }
21636
21774
  }
21637
21775
  else {
@@ -21639,14 +21777,19 @@ class SolanaMobileWalletProvider {
21639
21777
  versionedTx.message.recentBlockhash = blockhash;
21640
21778
  }
21641
21779
  if (isSurfnet) {
21642
- // Surfnet: sign-only, then submit to our specific RPC
21643
- const signedTransactions = await transact(async (wallet) => {
21644
- await this.reauthorizeWallet(wallet);
21645
- return wallet.signTransactions({ transactions: [transaction] });
21646
- }, this.getAssociationConfig());
21647
- const signedTx = signedTransactions[0];
21780
+ // Surfnet: sign locally via wallet-standard, submit manually
21781
+ // to the Surfnet RPC. Don't route through signAndSendTransaction
21782
+ // because the wallet would submit to its own RPC.
21783
+ const signTxFeat = getSignTransactionFeature(wallet);
21784
+ const wireBytes = txToWireBytes(transaction);
21785
+ const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
21786
+ if (!results || results.length === 0) {
21787
+ throw new Error('MWA returned no signed transaction');
21788
+ }
21789
+ const { signedTransaction: signedBytes } = results[0];
21790
+ const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
21648
21791
  const signature = await connection.sendRawTransaction(signedTx.serialize(), {
21649
- preflightCommitment: 'confirmed'
21792
+ preflightCommitment: 'confirmed',
21650
21793
  });
21651
21794
  const confirmation = await connection.confirmTransaction({
21652
21795
  signature,
@@ -21658,15 +21801,20 @@ class SolanaMobileWalletProvider {
21658
21801
  }
21659
21802
  return signature;
21660
21803
  }
21661
- // Non-surfnet: use signAndSendTransactions for wallet-optimized submission
21662
- const signatures = await transact(async (wallet) => {
21663
- await this.reauthorizeWallet(wallet);
21664
- return wallet.signAndSendTransactions({
21665
- transactions: [transaction],
21666
- commitment: 'confirmed',
21667
- });
21668
- }, this.getAssociationConfig());
21669
- const signature = signatures[0];
21804
+ // Non-Surfnet: wallet signs and submits to its own RPC.
21805
+ const signSendFeat = getSignAndSendTransactionFeature(wallet);
21806
+ const wireBytes = txToWireBytes(transaction);
21807
+ const results = await signSendFeat.signAndSendTransaction({
21808
+ account,
21809
+ transaction: wireBytes,
21810
+ chain,
21811
+ options: { commitment: 'confirmed' },
21812
+ });
21813
+ if (!results || results.length === 0) {
21814
+ throw new Error('MWA returned no signature');
21815
+ }
21816
+ const { signature: sigBytes } = results[0];
21817
+ const signature = base58.encode(sigBytes);
21670
21818
  await confirmAndCheckTransaction(connection, signature);
21671
21819
  return signature;
21672
21820
  }
@@ -21692,16 +21840,14 @@ class SolanaMobileWalletProvider {
21692
21840
  if (!solTransactionData) {
21693
21841
  throw new Error('Solana transaction data is required for mobile wallet');
21694
21842
  }
21695
- if (!this.publicKeyObj || !this.authorizedPublicKey) {
21696
- await this.login();
21697
- }
21698
- await loadMwaProtocol();
21699
- const { transact } = mwaProtocolModule;
21843
+ const account = await this.ensureAuthorized();
21844
+ const connectedPubkey = new web3_js.PublicKey(account.publicKey);
21845
+ const wallet = await this.ensureWallet();
21846
+ const chain = this.getChain();
21700
21847
  const rpcUrl = this.getRpcUrl(solTransactionData.network);
21701
21848
  const connection = new web3_js.Connection(rpcUrl, 'confirmed');
21702
21849
  const isSurfnet = rpcUrl === SURFNET_RPC_URL$2;
21703
21850
  try {
21704
- const publicKey = this.publicKeyObj;
21705
21851
  const remainingAccounts = convertRemainingAccounts(solTransactionData.txArgs[0].remainingAccounts);
21706
21852
  let app_id = solTransactionData.appId;
21707
21853
  if (typeof window !== 'undefined' && window.CUSTOM_TAROBASE_APP_ID_HEADER) {
@@ -21710,9 +21856,9 @@ class SolanaMobileWalletProvider {
21710
21856
  if (!app_id) {
21711
21857
  throw new Error('App ID is required');
21712
21858
  }
21713
- // Create a mock wallet adapter for Anchor (only publicKey is needed for building TX)
21859
+ // Mock wallet adapter for Anchor only publicKey is read during build.
21714
21860
  const mockWalletAdapter = {
21715
- publicKey,
21861
+ publicKey: connectedPubkey,
21716
21862
  signTransaction: async (tx) => tx,
21717
21863
  signAllTransactions: async (txs) => txs,
21718
21864
  };
@@ -21730,10 +21876,12 @@ class SolanaMobileWalletProvider {
21730
21876
  }
21731
21877
  let tx;
21732
21878
  if (solTransactionData.signedTransaction) {
21879
+ // Server has co-signed a CPI attestation. Do NOT mutate its
21880
+ // blockhash — that would invalidate the server's signature.
21733
21881
  tx = web3_js.VersionedTransaction.deserialize(bufferExports.Buffer.from(solTransactionData.signedTransaction, 'base64'));
21734
21882
  }
21735
21883
  else {
21736
- const result = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, publicKey, {
21884
+ const result = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, connectedPubkey, {
21737
21885
  app_id,
21738
21886
  documents: solTransactionData.txArgs[0].setDocumentData,
21739
21887
  delete_paths: solTransactionData.txArgs[0].deletePaths,
@@ -21741,11 +21889,16 @@ class SolanaMobileWalletProvider {
21741
21889
  }, finalDeduped, solTransactionData.lutKey, solTransactionData.preInstructions, false, solTransactionData.additionalLutAddresses);
21742
21890
  tx = result.tx;
21743
21891
  }
21892
+ // Sign-only branch — sign the tx but don't submit.
21744
21893
  if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
21745
- const [signedTx] = await transact(async (wallet) => {
21746
- await this.reauthorizeWallet(wallet);
21747
- return wallet.signTransactions({ transactions: [tx] });
21748
- }, this.getAssociationConfig());
21894
+ const signTxFeat = getSignTransactionFeature(wallet);
21895
+ const wireBytes = txToWireBytes(tx);
21896
+ const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
21897
+ if (!results || results.length === 0) {
21898
+ throw new Error('MWA returned no signed transaction');
21899
+ }
21900
+ const { signedTransaction: signedBytes } = results[0];
21901
+ const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
21749
21902
  return {
21750
21903
  signedTransaction: signedTx,
21751
21904
  blockNumber: 0,
@@ -21754,14 +21907,18 @@ class SolanaMobileWalletProvider {
21754
21907
  };
21755
21908
  }
21756
21909
  if (isSurfnet) {
21757
- // Surfnet: sign then submit manually to our RPC
21758
- const [signedTx] = await transact(async (wallet) => {
21759
- await this.reauthorizeWallet(wallet);
21760
- return wallet.signTransactions({ transactions: [tx] });
21761
- }, this.getAssociationConfig());
21910
+ // Surfnet: sign locally via wallet-standard, submit manually.
21911
+ const signTxFeat = getSignTransactionFeature(wallet);
21912
+ const wireBytes = txToWireBytes(tx);
21913
+ const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
21914
+ if (!results || results.length === 0) {
21915
+ throw new Error('MWA returned no signed transaction');
21916
+ }
21917
+ const { signedTransaction: signedBytes } = results[0];
21918
+ const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
21762
21919
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
21763
21920
  const signature = await connection.sendRawTransaction(signedTx.serialize(), {
21764
- preflightCommitment: 'confirmed'
21921
+ preflightCommitment: 'confirmed',
21765
21922
  });
21766
21923
  const confirmation = await connection.confirmTransaction({
21767
21924
  signature,
@@ -21773,7 +21930,7 @@ class SolanaMobileWalletProvider {
21773
21930
  }
21774
21931
  const txInfo = await connection.getParsedTransaction(signature, {
21775
21932
  maxSupportedTransactionVersion: 0,
21776
- commitment: 'confirmed'
21933
+ commitment: 'confirmed',
21777
21934
  });
21778
21935
  return {
21779
21936
  transactionSignature: signature,
@@ -21782,15 +21939,20 @@ class SolanaMobileWalletProvider {
21782
21939
  data: txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta,
21783
21940
  };
21784
21941
  }
21785
- // Non-surfnet: use signAndSendTransactions
21786
- const signatures = await transact(async (wallet) => {
21787
- await this.reauthorizeWallet(wallet);
21788
- return wallet.signAndSendTransactions({
21789
- transactions: [tx],
21790
- commitment: 'confirmed',
21791
- });
21792
- }, this.getAssociationConfig());
21793
- const signature = signatures[0];
21942
+ // Non-Surfnet: wallet signs and submits to its own RPC.
21943
+ const signSendFeat = getSignAndSendTransactionFeature(wallet);
21944
+ const wireBytes = txToWireBytes(tx);
21945
+ const results = await signSendFeat.signAndSendTransaction({
21946
+ account,
21947
+ transaction: wireBytes,
21948
+ chain,
21949
+ options: { commitment: 'confirmed' },
21950
+ });
21951
+ if (!results || results.length === 0) {
21952
+ throw new Error('MWA returned no signature');
21953
+ }
21954
+ const { signature: sigBytes } = results[0];
21955
+ const signature = base58.encode(sigBytes);
21794
21956
  const txInfo = await confirmAndCheckTransaction(connection, signature);
21795
21957
  return {
21796
21958
  transactionSignature: signature,
@@ -21817,11 +21979,36 @@ class SolanaMobileWalletProvider {
21817
21979
  }
21818
21980
  }
21819
21981
  async getNativeMethods() {
21982
+ var _a, _b, _c;
21983
+ // Synchronous-ish state read; tolerate the wallet being unauthorized
21984
+ // (return nulls). Don't trigger ensureAuthorized() here — callers that
21985
+ // need the wallet active should sign through one of the sign methods.
21986
+ const wallet = this.wallet;
21987
+ if (!wallet) {
21988
+ return {
21989
+ authToken: null,
21990
+ walletUriBase: null,
21991
+ publicKey: null,
21992
+ base64Address: null,
21993
+ wallet: null,
21994
+ currentAuthorization: null,
21995
+ };
21996
+ }
21997
+ const acct = (_a = wallet.accounts) === null || _a === void 0 ? void 0 : _a[0];
21998
+ const auth = wallet.currentAuthorization;
21999
+ let publicKey = null;
22000
+ let base64Address = null;
22001
+ if (acct) {
22002
+ publicKey = new web3_js.PublicKey(acct.publicKey);
22003
+ base64Address = btoa(String.fromCharCode(...acct.publicKey));
22004
+ }
21820
22005
  return {
21821
- authToken: this.authToken,
21822
- walletUriBase: this.walletUriBase,
21823
- publicKey: this.publicKeyObj,
21824
- base64Address: this.base64Address,
22006
+ authToken: (_b = auth === null || auth === void 0 ? void 0 : auth.auth_token) !== null && _b !== void 0 ? _b : null,
22007
+ walletUriBase: (_c = auth === null || auth === void 0 ? void 0 : auth.wallet_uri_base) !== null && _c !== void 0 ? _c : null,
22008
+ publicKey,
22009
+ base64Address,
22010
+ wallet,
22011
+ currentAuthorization: auth !== null && auth !== void 0 ? auth : null,
21825
22012
  };
21826
22013
  }
21827
22014
  /* ----------------------------------------------------------- *
@@ -22249,4 +22436,4 @@ exports.signSessionCreateMessage = signSessionCreateMessage;
22249
22436
  exports.signTransaction = signTransaction;
22250
22437
  exports.subscribe = subscribe;
22251
22438
  exports.useAuth = useAuth;
22252
- //# sourceMappingURL=index-DP0xF34Z.js.map
22439
+ //# sourceMappingURL=index-R7cvXys2.js.map