@trustware/sdk-staging 1.1.9-staging.3 → 1.1.9-staging.6

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.
@@ -579,6 +579,7 @@ declare class IdentityStore {
579
579
  resolve(chain?: WalletIdentityChainLike): WalletAddressResolution;
580
580
  }
581
581
 
582
+ type WalletConnectEcosystem = "evm" | "solana";
582
583
  type Status = "idle" | "detecting" | "connecting" | "connected" | "error";
583
584
  type ConnectedVia = "extension" | "walletconnect" | "direct" | null;
584
585
  type Listener = (s: Status) => void;
@@ -639,13 +640,16 @@ declare class WalletManager {
639
640
  error: string;
640
641
  api: WalletInterFaceAPI | null;
641
642
  } | undefined>;
642
- connectWalletConnect(walletCfg?: WalletConnectConfig): Promise<{
643
+ connectWalletConnect(walletCfg?: WalletConnectConfig, ecosystem?: WalletConnectEcosystem): Promise<{
643
644
  error: null;
644
645
  api: WalletInterFaceAPI;
645
646
  } | {
646
647
  error: string;
647
648
  api: null;
648
649
  }>;
650
+ private bindWalletConnectProviderEvents;
651
+ restoreWalletConnectSession(walletCfg?: WalletConnectConfig): Promise<WalletConnectEcosystem | null>;
652
+ cancelWalletConnectAttempt(): void;
649
653
  disconnect(wagmi?: WagmiBridge): Promise<void>;
650
654
  attachWallet(api: WalletInterFaceAPI): void;
651
655
  setStatus(s: Status): void;
@@ -659,7 +663,7 @@ declare class WalletManager {
659
663
  }
660
664
  declare const walletManager: WalletManager;
661
665
  declare function useWireDetectionIntoManager(): void;
662
- declare function useWalletConnectConnect(walletCfg?: WalletConnectConfig): () => Promise<{
666
+ declare function useWalletConnectConnect(walletCfg?: WalletConnectConfig): (ecosystem?: WalletConnectEcosystem) => Promise<{
663
667
  error: null;
664
668
  api: WalletInterFaceAPI;
665
669
  } | {
@@ -673,6 +677,7 @@ declare function useWalletInfo(wagmi?: WagmiBridge): {
673
677
  connectedVia: ConnectedVia;
674
678
  walletType: "walletconnect" | "other";
675
679
  status: Status;
680
+ detected: DetectedWallet[];
676
681
  disconnect: () => Promise<void>;
677
682
  };
678
683
  declare function useWalletExternalDisconnect(cb: () => void): void;
@@ -579,6 +579,7 @@ declare class IdentityStore {
579
579
  resolve(chain?: WalletIdentityChainLike): WalletAddressResolution;
580
580
  }
581
581
 
582
+ type WalletConnectEcosystem = "evm" | "solana";
582
583
  type Status = "idle" | "detecting" | "connecting" | "connected" | "error";
583
584
  type ConnectedVia = "extension" | "walletconnect" | "direct" | null;
584
585
  type Listener = (s: Status) => void;
@@ -639,13 +640,16 @@ declare class WalletManager {
639
640
  error: string;
640
641
  api: WalletInterFaceAPI | null;
641
642
  } | undefined>;
642
- connectWalletConnect(walletCfg?: WalletConnectConfig): Promise<{
643
+ connectWalletConnect(walletCfg?: WalletConnectConfig, ecosystem?: WalletConnectEcosystem): Promise<{
643
644
  error: null;
644
645
  api: WalletInterFaceAPI;
645
646
  } | {
646
647
  error: string;
647
648
  api: null;
648
649
  }>;
650
+ private bindWalletConnectProviderEvents;
651
+ restoreWalletConnectSession(walletCfg?: WalletConnectConfig): Promise<WalletConnectEcosystem | null>;
652
+ cancelWalletConnectAttempt(): void;
649
653
  disconnect(wagmi?: WagmiBridge): Promise<void>;
650
654
  attachWallet(api: WalletInterFaceAPI): void;
651
655
  setStatus(s: Status): void;
@@ -659,7 +663,7 @@ declare class WalletManager {
659
663
  }
660
664
  declare const walletManager: WalletManager;
661
665
  declare function useWireDetectionIntoManager(): void;
662
- declare function useWalletConnectConnect(walletCfg?: WalletConnectConfig): () => Promise<{
666
+ declare function useWalletConnectConnect(walletCfg?: WalletConnectConfig): (ecosystem?: WalletConnectEcosystem) => Promise<{
663
667
  error: null;
664
668
  api: WalletInterFaceAPI;
665
669
  } | {
@@ -673,6 +677,7 @@ declare function useWalletInfo(wagmi?: WagmiBridge): {
673
677
  connectedVia: ConnectedVia;
674
678
  walletType: "walletconnect" | "other";
675
679
  status: Status;
680
+ detected: DetectedWallet[];
676
681
  disconnect: () => Promise<void>;
677
682
  };
678
683
  declare function useWalletExternalDisconnect(cb: () => void): void;
@@ -12265,7 +12265,7 @@ var init_constants = __esm({
12265
12265
  "src/constants.ts"() {
12266
12266
  "use strict";
12267
12267
  SDK_NAME = "@trustware/sdk";
12268
- SDK_VERSION = "1.1.9-staging.3";
12268
+ SDK_VERSION = "1.1.9-staging.6";
12269
12269
  API_ROOT = "https://bv-staging-api.trustware.io";
12270
12270
  API_PREFIX = "/api";
12271
12271
  }
@@ -12241,7 +12241,7 @@ var init_constants = __esm({
12241
12241
  "src/constants.ts"() {
12242
12242
  "use strict";
12243
12243
  SDK_NAME = "@trustware/sdk";
12244
- SDK_VERSION = "1.1.9-staging.3";
12244
+ SDK_VERSION = "1.1.9-staging.6";
12245
12245
  API_ROOT = "https://bv-staging-api.trustware.io";
12246
12246
  API_PREFIX = "/api";
12247
12247
  }
package/dist/wallet.cjs CHANGED
@@ -250,7 +250,7 @@ var init_constants = __esm({
250
250
  "src/constants.ts"() {
251
251
  "use strict";
252
252
  SDK_NAME = "@trustware/sdk";
253
- SDK_VERSION = "1.1.9-staging.3";
253
+ SDK_VERSION = "1.1.9-staging.6";
254
254
  API_ROOT = "https://bv-staging-api.trustware.io";
255
255
  API_PREFIX = "/api";
256
256
  WALLETCONNECT_PROJECT_ID = "72ea74c400f5111d43aea638d7d83a24";
@@ -1340,21 +1340,28 @@ function formatDeepLink(id, currentUrl) {
1340
1340
  const enc = encodeURIComponent(currentUrl);
1341
1341
  switch (id) {
1342
1342
  // EVM
1343
+ // MetaMask's dapp browser also exposes its Wallet Standard Solana
1344
+ // provider in the same session, so "metamask-solana" reuses this link.
1343
1345
  case "metamask":
1346
+ case "metamask-solana":
1344
1347
  return `metamask://dapp/${currentUrl}`;
1345
1348
  case "coinbase":
1346
1349
  return `coinbase://wallet/dapp?url=${enc}`;
1347
1350
  case "rainbow":
1348
- return `rainbow://connect?uri=${enc}`;
1351
+ return `https://rainbow.me/dapp?url=${enc}`;
1349
1352
  case "trust":
1350
1353
  return `https://link.trustwallet.com/open_url?coin_id=60&url=${enc}`;
1351
1354
  case "okx":
1352
1355
  return `okx://wallet/dapp/url?dappUrl=${enc}`;
1353
1356
  // Solana
1357
+ // Phantom is one app with one in-app browser — browsing there injects
1358
+ // both window.ethereum and window.phantom.solana, so "phantom-evm"
1359
+ // reuses the same browse link as "phantom-solana".
1354
1360
  case "phantom-solana":
1355
- return `phantom://browse/${enc}`;
1361
+ case "phantom-evm":
1362
+ return `https://phantom.app/ul/browse/${enc}?ref=${enc}`;
1356
1363
  case "solflare":
1357
- return `solflare://ul/v1/browse/${enc}`;
1364
+ return `https://solflare.com/ul/v1/browse/${enc}?ref=${enc}`;
1358
1365
  case "backpack":
1359
1366
  return `https://backpack.app/ul/v1/browse/${enc}?ref=${enc}`;
1360
1367
  // No confirmed deep link scheme
@@ -1503,8 +1510,10 @@ var init_metadata = __esm({
1503
1510
  homepage: "https://phantom.app/",
1504
1511
  ios: "https://apps.apple.com/app/phantom-crypto-wallet/id1598432977",
1505
1512
  android: "https://play.google.com/store/apps/details?id=app.phantom",
1506
- detectFlags: ["isPhantom"]
1507
- // No EVM dapp browser deep linkfalls back to app store
1513
+ detectFlags: ["isPhantom"],
1514
+ // Same app/in-app browser as "phantom-solana"browsing there injects
1515
+ // window.ethereum too.
1516
+ deepLink: (url) => formatDeepLink("phantom-evm", url) ?? ""
1508
1517
  },
1509
1518
  {
1510
1519
  id: "phantom-solana",
@@ -1552,8 +1561,10 @@ var init_metadata = __esm({
1552
1561
  emoji: "\u{1F98A}",
1553
1562
  homepage: "https://metamask.io/",
1554
1563
  ios: "https://apps.apple.com/app/metamask/id1438144202",
1555
- android: "https://play.google.com/store/apps/details?id=io.metamask"
1556
- // No Solana-specific deep link for MetaMask
1564
+ android: "https://play.google.com/store/apps/details?id=io.metamask",
1565
+ // Same app/in-app browser as "metamask" — its Wallet Standard Solana
1566
+ // provider is exposed in that same browse session.
1567
+ deepLink: (url) => formatDeepLink("metamask-solana", url) ?? ""
1557
1568
  },
1558
1569
  // ── Extension/desktop only — hidden on mobile ─────────────────────────────
1559
1570
  {
@@ -2076,7 +2087,7 @@ var init_walletconnect = __esm({
2076
2087
  solanaMainnet = {
2077
2088
  id: 900,
2078
2089
  chainNamespace: "solana",
2079
- caipNetworkId: "solana:5eykt4UsFv8P8NJdTREpY1vzqAQ3H1FQ",
2090
+ caipNetworkId: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
2080
2091
  name: "Solana Mainnet",
2081
2092
  nativeCurrency: {
2082
2093
  name: "Solana",
@@ -2954,8 +2965,62 @@ function getChainMeta(chainId) {
2954
2965
  rpcUrls: chain.rpcUrls.default.http
2955
2966
  };
2956
2967
  }
2957
- async function buildWalletConnectAPI(walletCfg) {
2968
+ function extractSolanaAddress(connector) {
2969
+ const caipAccount = connector.provider.session?.namespaces?.solana?.accounts?.[0];
2970
+ if (!caipAccount) return null;
2971
+ return caipAccount.split(":")[2] ?? null;
2972
+ }
2973
+ function buildWalletConnectSolanaProvider(connector) {
2974
+ return {
2975
+ get publicKey() {
2976
+ const address = extractSolanaAddress(connector);
2977
+ return address ? { toString: () => address } : void 0;
2978
+ },
2979
+ async connect() {
2980
+ const address = extractSolanaAddress(connector);
2981
+ if (!address) {
2982
+ throw new Error(
2983
+ "This wallet did not approve a Solana account over WalletConnect."
2984
+ );
2985
+ }
2986
+ return { publicKey: { toString: () => address } };
2987
+ },
2988
+ async disconnect() {
2989
+ },
2990
+ async signTransaction(transaction) {
2991
+ const tx = transaction;
2992
+ const rawBytes = "version" in tx ? tx.serialize() : tx.serialize({
2993
+ requireAllSignatures: false,
2994
+ verifySignatures: false
2995
+ });
2996
+ const result = await connector.provider.request(
2997
+ {
2998
+ method: "solana_signTransaction",
2999
+ params: { transaction: encodeBase64(rawBytes) }
3000
+ },
3001
+ solanaMainnet.caipNetworkId
3002
+ );
3003
+ if (!result.transaction) {
3004
+ throw new Error(
3005
+ "WalletConnect wallet did not return a signed Solana transaction."
3006
+ );
3007
+ }
3008
+ const signedBytes = decodeBase64(result.transaction);
3009
+ return { serialize: () => signedBytes };
3010
+ },
3011
+ on() {
3012
+ },
3013
+ off() {
3014
+ },
3015
+ removeListener() {
3016
+ }
3017
+ };
3018
+ }
3019
+ async function buildWalletConnectAPI(walletCfg, ecosystem = "evm") {
2958
3020
  const connector = await getUniversalConnector(walletCfg);
3021
+ if (ecosystem === "solana") {
3022
+ return toSolanaWalletInterface(buildWalletConnectSolanaProvider(connector));
3023
+ }
2959
3024
  const provider = connector.provider;
2960
3025
  const api = {
2961
3026
  ecosystem: "evm",
@@ -3031,7 +3096,7 @@ function useWireDetectionIntoManager() {
3031
3096
  function useWalletConnectConnect(walletCfg) {
3032
3097
  const cfgRef = { current: walletCfg };
3033
3098
  return (0, import_react2.useCallback)(
3034
- () => walletManager.connectWalletConnect(cfgRef.current),
3099
+ (ecosystem) => walletManager.connectWalletConnect(cfgRef.current, ecosystem),
3035
3100
  []
3036
3101
  );
3037
3102
  }
@@ -3051,6 +3116,7 @@ function useWalletInfo(wagmi) {
3051
3116
  connectedVia: snapshot.connectedVia,
3052
3117
  walletType: snapshot.walletType,
3053
3118
  status: snapshot.status,
3119
+ detected: snapshot.detected,
3054
3120
  disconnect
3055
3121
  };
3056
3122
  }
@@ -3203,44 +3269,39 @@ var init_manager = __esm({
3203
3269
  this.emit();
3204
3270
  }
3205
3271
  }
3206
- async connectWalletConnect(walletCfg) {
3207
- if (this._status === "connected" && this._connectedVia === "walletconnect" && this._wallet) {
3272
+ async connectWalletConnect(walletCfg, ecosystem = "evm") {
3273
+ if (this._status === "connected" && this._connectedVia === "walletconnect" && this._wallet && this._wallet.ecosystem === ecosystem) {
3208
3274
  this.emit();
3209
3275
  return { error: null, api: this._wallet };
3210
3276
  }
3277
+ if (this._connectedVia === "walletconnect" && this._wallet) {
3278
+ await this._wallet.disconnect?.().catch(() => {
3279
+ });
3280
+ resetUniversalConnector();
3281
+ }
3211
3282
  this._status = "connecting";
3212
3283
  this.clearConnectedState();
3213
3284
  this.emit();
3214
3285
  try {
3215
3286
  const connector = await getUniversalConnector(walletCfg);
3216
3287
  await connector.connect();
3217
- const api = await buildWalletConnectAPI(walletCfg);
3288
+ const api = await buildWalletConnectAPI(walletCfg, ecosystem);
3289
+ try {
3290
+ await api.getAddress();
3291
+ } catch {
3292
+ await api.disconnect?.().catch(() => {
3293
+ });
3294
+ resetUniversalConnector();
3295
+ throw new Error(
3296
+ `This wallet did not approve a${ecosystem === "evm" ? "n" : ""} ${ecosystem === "evm" ? "EVM" : "Solana"} account over WalletConnect.`
3297
+ );
3298
+ }
3218
3299
  this._wallet = api;
3219
3300
  this._connectedVia = "walletconnect";
3220
3301
  this._connectedWalletId = "walletconnect";
3221
- const provider = connector.provider;
3222
- this._providerCleanup = bindWalletConnectEvents(provider, {
3223
- onAccountsChanged: (accounts) => {
3224
- if (accounts.length === 0) {
3225
- this.fullReset();
3226
- this.triggerExternalDisconnect();
3227
- this.emit();
3228
- return;
3229
- }
3230
- void this.syncIdentityFromWallet("walletconnect");
3231
- this.emit();
3232
- },
3233
- onChainChanged: () => {
3234
- void this.syncIdentityFromWallet("walletconnect");
3235
- this.emit();
3236
- },
3237
- onDisconnect: () => {
3238
- this.fullReset();
3239
- resetUniversalConnector();
3240
- this.triggerExternalDisconnect();
3241
- this.emit();
3242
- }
3243
- });
3302
+ this._providerCleanup = this.bindWalletConnectProviderEvents(
3303
+ connector.provider
3304
+ );
3244
3305
  await this.syncIdentityFromWallet("walletconnect");
3245
3306
  this._status = "connected";
3246
3307
  this._error = null;
@@ -3255,6 +3316,100 @@ var init_manager = __esm({
3255
3316
  return { error: message, api: null };
3256
3317
  }
3257
3318
  }
3319
+ bindWalletConnectProviderEvents(provider) {
3320
+ return bindWalletConnectEvents(provider, {
3321
+ onAccountsChanged: (accounts) => {
3322
+ if (accounts.length === 0) {
3323
+ this.fullReset();
3324
+ this.triggerExternalDisconnect();
3325
+ this.emit();
3326
+ return;
3327
+ }
3328
+ void this.syncIdentityFromWallet("walletconnect");
3329
+ this.emit();
3330
+ },
3331
+ onChainChanged: () => {
3332
+ void this.syncIdentityFromWallet("walletconnect");
3333
+ this.emit();
3334
+ },
3335
+ onDisconnect: () => {
3336
+ this.fullReset();
3337
+ resetUniversalConnector();
3338
+ this.triggerExternalDisconnect();
3339
+ this.emit();
3340
+ }
3341
+ });
3342
+ }
3343
+ // WalletConnect's own SignClient auto-restores the last persisted session
3344
+ // from storage on every init — including after a fresh page load — but
3345
+ // that restoration happens silently inside the library. Nothing calls back
3346
+ // into our code for it. On mobile, backgrounding the tab to approve in a
3347
+ // wallet app can cause the OS to reload the page before the original
3348
+ // connect() promise ever resolves, so the connect flow that triggered the
3349
+ // approval never gets to record it as "connected" here — even though
3350
+ // WalletConnect itself already has a live, approved session sitting in
3351
+ // storage. Call this on mount to pick that back up.
3352
+ async restoreWalletConnectSession(walletCfg) {
3353
+ if (this._status === "connected" && this._connectedVia === "walletconnect") {
3354
+ return this._wallet?.ecosystem === "solana" ? "solana" : "evm";
3355
+ }
3356
+ if (typeof window === "undefined") return null;
3357
+ try {
3358
+ if (!Object.keys(window.localStorage).some((key) => key.startsWith("wc@2"))) {
3359
+ return null;
3360
+ }
3361
+ } catch {
3362
+ }
3363
+ let connector;
3364
+ try {
3365
+ connector = await getUniversalConnector(walletCfg);
3366
+ } catch (e2) {
3367
+ console.warn(
3368
+ "[Trustware SDK] Failed to restore WalletConnect session:",
3369
+ e2
3370
+ );
3371
+ return null;
3372
+ }
3373
+ const session = connector.provider.session;
3374
+ if (!session) return null;
3375
+ const ecosystem = session.namespaces?.solana?.accounts?.length ? "solana" : session.namespaces?.eip155?.accounts?.length ? "evm" : null;
3376
+ if (!ecosystem) return null;
3377
+ try {
3378
+ const api = await buildWalletConnectAPI(walletCfg, ecosystem);
3379
+ this._wallet = api;
3380
+ this._connectedVia = "walletconnect";
3381
+ this._connectedWalletId = "walletconnect";
3382
+ this._providerCleanup = this.bindWalletConnectProviderEvents(
3383
+ connector.provider
3384
+ );
3385
+ await this.syncIdentityFromWallet("walletconnect");
3386
+ this._status = "connected";
3387
+ this._error = null;
3388
+ this.emit();
3389
+ return ecosystem;
3390
+ } catch {
3391
+ return null;
3392
+ }
3393
+ }
3394
+ // Forcibly abandon an in-progress connect() call the caller has decided is
3395
+ // stuck (e.g. the UI's own connect timeout elapsed with no response).
3396
+ // There's no clean way to cancel a pending WalletConnect pairing proposal
3397
+ // from this side, so this tears down the whole connector — the next
3398
+ // connect attempt starts against a brand new SignClient/pairing instead of
3399
+ // racing the abandoned one, which would otherwise risk reproducing the
3400
+ // "No matching key. proposal" class of error a real retry needs to avoid.
3401
+ cancelWalletConnectAttempt() {
3402
+ if (this._connectedVia === "walletconnect" && this._status === "connected") {
3403
+ return;
3404
+ }
3405
+ resetUniversalConnector();
3406
+ if (this._status === "connecting") {
3407
+ this.clearConnectedState();
3408
+ this._status = "idle";
3409
+ this._error = null;
3410
+ this.emit();
3411
+ }
3412
+ }
3258
3413
  async disconnect(wagmi) {
3259
3414
  if (wagmi && this._connectedVia === "extension") {
3260
3415
  await wagmi.disconnect().catch(() => {
@@ -4121,7 +4276,9 @@ __export(wallet_exports, {
4121
4276
  buildDetectedWalletFromProvider: () => buildDetectedWalletFromProvider,
4122
4277
  connectDetectedWallet: () => connectDetectedWallet,
4123
4278
  createWalletConnectEntry: () => createWalletConnectEntry,
4279
+ decodeBase64: () => decodeBase64,
4124
4280
  detectSolanaWallets: () => detectSolanaWallets,
4281
+ encodeBase64: () => encodeBase64,
4125
4282
  formatDeepLink: () => formatDeepLink,
4126
4283
  formatWalletConnectDeepLink: () => formatWalletConnectDeepLink,
4127
4284
  formatWalletConnectDeepLinkForWallet: () => formatWalletConnectDeepLinkForWallet,
@@ -4149,7 +4306,9 @@ init_wallets2();
4149
4306
  buildDetectedWalletFromProvider,
4150
4307
  connectDetectedWallet,
4151
4308
  createWalletConnectEntry,
4309
+ decodeBase64,
4152
4310
  detectSolanaWallets,
4311
+ encodeBase64,
4153
4312
  formatDeepLink,
4154
4313
  formatWalletConnectDeepLink,
4155
4314
  formatWalletConnectDeepLinkForWallet,