@silentswap/sdk 0.1.4 → 0.1.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/chain.d.ts CHANGED
@@ -13,6 +13,19 @@ import type { Connector } from 'wagmi';
13
13
  export declare function ensureChain(chainId: number, walletClient: WalletClient, connector: Connector, options?: {
14
14
  required?: boolean;
15
15
  }): Promise<WalletClient>;
16
+ /**
17
+ * Ping the WalletConnect session to ensure the relay WebSocket is alive.
18
+ * Browsers cannot detect stale WebSockets (no ping/pong frames), so a signing
19
+ * request sent on a dead socket silently vanishes. Pinging first forces
20
+ * the relay to reconnect if the connection dropped.
21
+ *
22
+ * @param connector - The wagmi connector (must be WalletConnect)
23
+ * @returns true if ping succeeded, false if it failed or connector is not WalletConnect
24
+ */
25
+ export declare function pingWalletConnectSession(connector: {
26
+ type: string;
27
+ getProvider: () => Promise<unknown>;
28
+ }): Promise<boolean>;
16
29
  /**
17
30
  * Create a public client with RPC fallback configuration
18
31
  *
package/dist/chain.js CHANGED
@@ -13,6 +13,13 @@ import { H_RPCS } from './rpc.js';
13
13
  */
14
14
  export async function ensureChain(chainId, walletClient, connector, options) {
15
15
  const required = options?.required ?? true;
16
+ console.log('[ensureChain] called', {
17
+ targetChainId: chainId,
18
+ required,
19
+ connectorName: connector.name,
20
+ connectorType: connector.type,
21
+ walletClientChain: walletClient.chain?.id,
22
+ });
16
23
  // Check current chain
17
24
  let currentChainId;
18
25
  try {
@@ -22,35 +29,92 @@ export async function ensureChain(chainId, walletClient, connector, options) {
22
29
  // If we can't get chain ID, assume we need to switch
23
30
  currentChainId = -1;
24
31
  }
32
+ console.log('[ensureChain] currentChainId:', currentChainId, 'targetChainId:', chainId, 'needsSwitch:', currentChainId !== chainId);
25
33
  if (currentChainId !== chainId) {
34
+ let switchSucceeded = false;
26
35
  try {
27
36
  // Try to switch chain
37
+ console.log('[ensureChain] attempting switchChain ...', { hasSwitchChain: !!connector.switchChain });
28
38
  await connector.switchChain?.({ chainId });
39
+ switchSucceeded = true;
40
+ console.log('[ensureChain] switchChain succeeded');
29
41
  }
30
42
  catch (switchError) {
43
+ console.warn('[ensureChain] switchChain failed', {
44
+ error: switchError instanceof Error ? switchError.message : switchError,
45
+ required,
46
+ });
31
47
  if (required) {
32
48
  throw new Error(`Failed to switch to chain ${chainId}`);
33
49
  }
34
50
  // Non-required: chain switch failed (e.g. Trust Wallet via WalletConnect
35
- // doesn't support programmatic chain switching). Return the original client
36
- // signTypedData works regardless of the active chain since chainId is
37
- // part of the signed EIP-712 data, not a prerequisite for signing.
38
- return walletClient;
51
+ // doesn't support programmatic chain switching). Still recreate the
52
+ // walletClient from the provider so the WalletConnect transport is fresh
53
+ // TrustWallet silently drops signTypedData when the client's chain scope
54
+ // doesn't match its active session chain.
39
55
  }
40
- // After chain switch, create a fresh walletClient bound to the new chain.
56
+ // Always recreate walletClient from the provider after a chain change attempt.
41
57
  // Critical for WalletConnect: the old walletClient's chain scope (e.g. eip155:43114)
42
- // doesn't match the new active chain, so signing requests get silently dropped
43
- // by the mobile wallet.
58
+ // doesn't match the active chain, so signing requests get silently dropped
59
+ // by the mobile wallet. This applies both after a successful switch AND a failed
60
+ // one — the provider's internal state may still have updated even if switchChain threw.
61
+ console.log('[ensureChain] recreating walletClient from provider ...', { switchSucceeded });
44
62
  const provider = await connector.getProvider();
45
63
  const chain = getChainById(chainId);
46
- return createWalletClient({
64
+ const newClient = createWalletClient({
47
65
  account: walletClient.account,
48
66
  chain,
49
67
  transport: custom(provider),
50
68
  });
69
+ console.log('[ensureChain] new walletClient created', {
70
+ chainId: newClient.chain?.id,
71
+ account: newClient.account?.address,
72
+ });
73
+ return newClient;
51
74
  }
75
+ console.log('[ensureChain] already on correct chain, returning existing walletClient');
52
76
  return walletClient;
53
77
  }
78
+ /**
79
+ * Ping the WalletConnect session to ensure the relay WebSocket is alive.
80
+ * Browsers cannot detect stale WebSockets (no ping/pong frames), so a signing
81
+ * request sent on a dead socket silently vanishes. Pinging first forces
82
+ * the relay to reconnect if the connection dropped.
83
+ *
84
+ * @param connector - The wagmi connector (must be WalletConnect)
85
+ * @returns true if ping succeeded, false if it failed or connector is not WalletConnect
86
+ */
87
+ export async function pingWalletConnectSession(connector) {
88
+ if (connector.type !== 'walletConnect')
89
+ return true; // Not WC, nothing to ping
90
+ try {
91
+ const provider = await connector.getProvider();
92
+ const topic = provider?.session?.topic;
93
+ // Try both paths: Reown (provider.client) and legacy WC (provider.signer.client)
94
+ const signClient = provider?.client?.ping ? provider.client : provider?.signer?.client;
95
+ if (!topic || !signClient?.ping) {
96
+ console.log('[pingWC] no session or sign client, skipping ping', {
97
+ hasTopic: !!topic,
98
+ hasClient: !!provider?.client,
99
+ hasClientPing: !!provider?.client?.ping,
100
+ hasSigner: !!provider?.signer,
101
+ hasSignerClient: !!provider?.signer?.client,
102
+ });
103
+ return true; // Can't ping, assume ok
104
+ }
105
+ console.log('[pingWC] pinging session ...');
106
+ await Promise.race([
107
+ signClient.ping({ topic }),
108
+ new Promise((_, reject) => setTimeout(() => reject(new Error('WC ping timeout')), 5000)),
109
+ ]);
110
+ console.log('[pingWC] ping OK');
111
+ return true;
112
+ }
113
+ catch (err) {
114
+ console.warn('[pingWC] ping failed, session may be stale:', err.message);
115
+ return false;
116
+ }
117
+ }
54
118
  /**
55
119
  * Create a public client with RPC fallback configuration
56
120
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@silentswap/sdk",
3
3
  "type": "module",
4
- "version": "0.1.4",
4
+ "version": "0.1.42",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
7
7
  "files": [