@abstraxn/signer-react 3.3.9 → 3.3.10
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/CHANGELOG.md +11 -0
- package/dist/src/hooks.d.ts +23 -17
- package/dist/src/hooks.js +22 -6
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/walletConnectMobile.d.ts +9 -5
- package/dist/src/walletConnectMobile.js +152 -51
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.3.10] - 2026-09-18
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Mobile WalletConnect reject / confirm / on-chain failure** (aligned with WC + EIP-1193):
|
|
12
|
+
- **Reject:** On return from MetaMask, force-resume the relay (time-bounded). Map EIP-1193 `4001` / WC `5000` to `User rejected the request`. If WC stays silent and pending nonce never moved, surface the same reject error so loaders clear.
|
|
13
|
+
- **Confirm:** WC success is a **tx hash** only. Gated chain poll recovers the hash when the relay drops after approve (success-only; does not invent rejects).
|
|
14
|
+
- **On-chain failure:** `useWaitForTxnReceipt` defaults to `throwOnRevert: true` so a mined `status: reverted` throws `Transaction reverted` (receipt check is dapp/RPC, not WalletConnect).
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- `isUserRejectionError`, `toUserRejectionError`, `forceResumeWalletConnectOnReturn`.
|
|
18
|
+
|
|
8
19
|
## [3.3.9] - 2026-09-17
|
|
9
20
|
|
|
10
21
|
### Fixed
|
package/dist/src/hooks.d.ts
CHANGED
|
@@ -8165,11 +8165,12 @@ export declare function useWalletClient(chain: any, rpcUrl?: string): {
|
|
|
8165
8165
|
[x: `bytes3[${string}]`]: undefined;
|
|
8166
8166
|
[x: `bytes1[${string}]`]: undefined;
|
|
8167
8167
|
[x: `bytes2[${string}]`]: undefined;
|
|
8168
|
+
[x: `bytes16[${string}]`]: undefined;
|
|
8169
|
+
[x: `bytes8[${string}]`]: undefined;
|
|
8168
8170
|
[x: `bytes4[${string}]`]: undefined;
|
|
8169
8171
|
[x: `bytes5[${string}]`]: undefined;
|
|
8170
8172
|
[x: `bytes6[${string}]`]: undefined;
|
|
8171
8173
|
[x: `bytes7[${string}]`]: undefined;
|
|
8172
|
-
[x: `bytes8[${string}]`]: undefined;
|
|
8173
8174
|
[x: `bytes9[${string}]`]: undefined;
|
|
8174
8175
|
[x: `bytes10[${string}]`]: undefined;
|
|
8175
8176
|
[x: `bytes11[${string}]`]: undefined;
|
|
@@ -8177,7 +8178,6 @@ export declare function useWalletClient(chain: any, rpcUrl?: string): {
|
|
|
8177
8178
|
[x: `bytes13[${string}]`]: undefined;
|
|
8178
8179
|
[x: `bytes14[${string}]`]: undefined;
|
|
8179
8180
|
[x: `bytes15[${string}]`]: undefined;
|
|
8180
|
-
[x: `bytes16[${string}]`]: undefined;
|
|
8181
8181
|
[x: `bytes17[${string}]`]: undefined;
|
|
8182
8182
|
[x: `bytes18[${string}]`]: undefined;
|
|
8183
8183
|
[x: `bytes19[${string}]`]: undefined;
|
|
@@ -8195,8 +8195,8 @@ export declare function useWalletClient(chain: any, rpcUrl?: string): {
|
|
|
8195
8195
|
[x: `bytes31[${string}]`]: undefined;
|
|
8196
8196
|
[x: `bytes32[${string}]`]: undefined;
|
|
8197
8197
|
[x: `int[${string}]`]: undefined;
|
|
8198
|
-
[x: `int8[${string}]`]: undefined;
|
|
8199
8198
|
[x: `int16[${string}]`]: undefined;
|
|
8199
|
+
[x: `int8[${string}]`]: undefined;
|
|
8200
8200
|
[x: `int24[${string}]`]: undefined;
|
|
8201
8201
|
[x: `int32[${string}]`]: undefined;
|
|
8202
8202
|
[x: `int40[${string}]`]: undefined;
|
|
@@ -8228,8 +8228,8 @@ export declare function useWalletClient(chain: any, rpcUrl?: string): {
|
|
|
8228
8228
|
[x: `int248[${string}]`]: undefined;
|
|
8229
8229
|
[x: `int256[${string}]`]: undefined;
|
|
8230
8230
|
[x: `uint[${string}]`]: undefined;
|
|
8231
|
-
[x: `uint8[${string}]`]: undefined;
|
|
8232
8231
|
[x: `uint16[${string}]`]: undefined;
|
|
8232
|
+
[x: `uint8[${string}]`]: undefined;
|
|
8233
8233
|
[x: `uint24[${string}]`]: undefined;
|
|
8234
8234
|
[x: `uint32[${string}]`]: undefined;
|
|
8235
8235
|
[x: `uint40[${string}]`]: undefined;
|
|
@@ -8267,11 +8267,12 @@ export declare function useWalletClient(chain: any, rpcUrl?: string): {
|
|
|
8267
8267
|
bytes3?: undefined;
|
|
8268
8268
|
bytes1?: undefined;
|
|
8269
8269
|
bytes2?: undefined;
|
|
8270
|
+
bytes16?: undefined;
|
|
8271
|
+
bytes8?: undefined;
|
|
8270
8272
|
bytes4?: undefined;
|
|
8271
8273
|
bytes5?: undefined;
|
|
8272
8274
|
bytes6?: undefined;
|
|
8273
8275
|
bytes7?: undefined;
|
|
8274
|
-
bytes8?: undefined;
|
|
8275
8276
|
bytes9?: undefined;
|
|
8276
8277
|
bytes10?: undefined;
|
|
8277
8278
|
bytes11?: undefined;
|
|
@@ -8279,7 +8280,6 @@ export declare function useWalletClient(chain: any, rpcUrl?: string): {
|
|
|
8279
8280
|
bytes13?: undefined;
|
|
8280
8281
|
bytes14?: undefined;
|
|
8281
8282
|
bytes15?: undefined;
|
|
8282
|
-
bytes16?: undefined;
|
|
8283
8283
|
bytes17?: undefined;
|
|
8284
8284
|
bytes18?: undefined;
|
|
8285
8285
|
bytes19?: undefined;
|
|
@@ -8296,8 +8296,8 @@ export declare function useWalletClient(chain: any, rpcUrl?: string): {
|
|
|
8296
8296
|
bytes30?: undefined;
|
|
8297
8297
|
bytes31?: undefined;
|
|
8298
8298
|
bytes32?: undefined;
|
|
8299
|
-
int8?: undefined;
|
|
8300
8299
|
int16?: undefined;
|
|
8300
|
+
int8?: undefined;
|
|
8301
8301
|
int24?: undefined;
|
|
8302
8302
|
int32?: undefined;
|
|
8303
8303
|
int40?: undefined;
|
|
@@ -8328,8 +8328,8 @@ export declare function useWalletClient(chain: any, rpcUrl?: string): {
|
|
|
8328
8328
|
int240?: undefined;
|
|
8329
8329
|
int248?: undefined;
|
|
8330
8330
|
int256?: undefined;
|
|
8331
|
-
uint8?: undefined;
|
|
8332
8331
|
uint16?: undefined;
|
|
8332
|
+
uint8?: undefined;
|
|
8333
8333
|
uint24?: undefined;
|
|
8334
8334
|
uint32?: undefined;
|
|
8335
8335
|
uint40?: undefined;
|
|
@@ -8811,10 +8811,16 @@ export declare function useSignAndSendTxn(provider: PublicClient): {
|
|
|
8811
8811
|
* ```
|
|
8812
8812
|
*/
|
|
8813
8813
|
export declare function useWaitForTxnReceipt(provider: PublicClient): {
|
|
8814
|
-
waitForTxnReceipt: ({ hash, confirmations, timeout, }: {
|
|
8814
|
+
waitForTxnReceipt: ({ hash, confirmations, timeout, throwOnRevert, }: {
|
|
8815
8815
|
hash: `0x${string}`;
|
|
8816
8816
|
confirmations?: number;
|
|
8817
8817
|
timeout?: number;
|
|
8818
|
+
/**
|
|
8819
|
+
* When true (default), a mined receipt with status reverted throws
|
|
8820
|
+
* `Transaction reverted` — on-chain failure is not a WalletConnect concern;
|
|
8821
|
+
* the dapp must check the receipt after receiving the hash.
|
|
8822
|
+
*/
|
|
8823
|
+
throwOnRevert?: boolean;
|
|
8818
8824
|
}) => Promise<TransactionReceipt>;
|
|
8819
8825
|
};
|
|
8820
8826
|
/**
|
|
@@ -13140,11 +13146,12 @@ export declare function useExternalWalletClient(): {
|
|
|
13140
13146
|
[x: `bytes3[${string}]`]: undefined;
|
|
13141
13147
|
[x: `bytes1[${string}]`]: undefined;
|
|
13142
13148
|
[x: `bytes2[${string}]`]: undefined;
|
|
13149
|
+
[x: `bytes16[${string}]`]: undefined;
|
|
13150
|
+
[x: `bytes8[${string}]`]: undefined;
|
|
13143
13151
|
[x: `bytes4[${string}]`]: undefined;
|
|
13144
13152
|
[x: `bytes5[${string}]`]: undefined;
|
|
13145
13153
|
[x: `bytes6[${string}]`]: undefined;
|
|
13146
13154
|
[x: `bytes7[${string}]`]: undefined;
|
|
13147
|
-
[x: `bytes8[${string}]`]: undefined;
|
|
13148
13155
|
[x: `bytes9[${string}]`]: undefined;
|
|
13149
13156
|
[x: `bytes10[${string}]`]: undefined;
|
|
13150
13157
|
[x: `bytes11[${string}]`]: undefined;
|
|
@@ -13152,7 +13159,6 @@ export declare function useExternalWalletClient(): {
|
|
|
13152
13159
|
[x: `bytes13[${string}]`]: undefined;
|
|
13153
13160
|
[x: `bytes14[${string}]`]: undefined;
|
|
13154
13161
|
[x: `bytes15[${string}]`]: undefined;
|
|
13155
|
-
[x: `bytes16[${string}]`]: undefined;
|
|
13156
13162
|
[x: `bytes17[${string}]`]: undefined;
|
|
13157
13163
|
[x: `bytes18[${string}]`]: undefined;
|
|
13158
13164
|
[x: `bytes19[${string}]`]: undefined;
|
|
@@ -13170,8 +13176,8 @@ export declare function useExternalWalletClient(): {
|
|
|
13170
13176
|
[x: `bytes31[${string}]`]: undefined;
|
|
13171
13177
|
[x: `bytes32[${string}]`]: undefined;
|
|
13172
13178
|
[x: `int[${string}]`]: undefined;
|
|
13173
|
-
[x: `int8[${string}]`]: undefined;
|
|
13174
13179
|
[x: `int16[${string}]`]: undefined;
|
|
13180
|
+
[x: `int8[${string}]`]: undefined;
|
|
13175
13181
|
[x: `int24[${string}]`]: undefined;
|
|
13176
13182
|
[x: `int32[${string}]`]: undefined;
|
|
13177
13183
|
[x: `int40[${string}]`]: undefined;
|
|
@@ -13203,8 +13209,8 @@ export declare function useExternalWalletClient(): {
|
|
|
13203
13209
|
[x: `int248[${string}]`]: undefined;
|
|
13204
13210
|
[x: `int256[${string}]`]: undefined;
|
|
13205
13211
|
[x: `uint[${string}]`]: undefined;
|
|
13206
|
-
[x: `uint8[${string}]`]: undefined;
|
|
13207
13212
|
[x: `uint16[${string}]`]: undefined;
|
|
13213
|
+
[x: `uint8[${string}]`]: undefined;
|
|
13208
13214
|
[x: `uint24[${string}]`]: undefined;
|
|
13209
13215
|
[x: `uint32[${string}]`]: undefined;
|
|
13210
13216
|
[x: `uint40[${string}]`]: undefined;
|
|
@@ -13242,11 +13248,12 @@ export declare function useExternalWalletClient(): {
|
|
|
13242
13248
|
bytes3?: undefined;
|
|
13243
13249
|
bytes1?: undefined;
|
|
13244
13250
|
bytes2?: undefined;
|
|
13251
|
+
bytes16?: undefined;
|
|
13252
|
+
bytes8?: undefined;
|
|
13245
13253
|
bytes4?: undefined;
|
|
13246
13254
|
bytes5?: undefined;
|
|
13247
13255
|
bytes6?: undefined;
|
|
13248
13256
|
bytes7?: undefined;
|
|
13249
|
-
bytes8?: undefined;
|
|
13250
13257
|
bytes9?: undefined;
|
|
13251
13258
|
bytes10?: undefined;
|
|
13252
13259
|
bytes11?: undefined;
|
|
@@ -13254,7 +13261,6 @@ export declare function useExternalWalletClient(): {
|
|
|
13254
13261
|
bytes13?: undefined;
|
|
13255
13262
|
bytes14?: undefined;
|
|
13256
13263
|
bytes15?: undefined;
|
|
13257
|
-
bytes16?: undefined;
|
|
13258
13264
|
bytes17?: undefined;
|
|
13259
13265
|
bytes18?: undefined;
|
|
13260
13266
|
bytes19?: undefined;
|
|
@@ -13271,8 +13277,8 @@ export declare function useExternalWalletClient(): {
|
|
|
13271
13277
|
bytes30?: undefined;
|
|
13272
13278
|
bytes31?: undefined;
|
|
13273
13279
|
bytes32?: undefined;
|
|
13274
|
-
int8?: undefined;
|
|
13275
13280
|
int16?: undefined;
|
|
13281
|
+
int8?: undefined;
|
|
13276
13282
|
int24?: undefined;
|
|
13277
13283
|
int32?: undefined;
|
|
13278
13284
|
int40?: undefined;
|
|
@@ -13303,8 +13309,8 @@ export declare function useExternalWalletClient(): {
|
|
|
13303
13309
|
int240?: undefined;
|
|
13304
13310
|
int248?: undefined;
|
|
13305
13311
|
int256?: undefined;
|
|
13306
|
-
uint8?: undefined;
|
|
13307
13312
|
uint16?: undefined;
|
|
13313
|
+
uint8?: undefined;
|
|
13308
13314
|
uint24?: undefined;
|
|
13309
13315
|
uint32?: undefined;
|
|
13310
13316
|
uint40?: undefined;
|
package/dist/src/hooks.js
CHANGED
|
@@ -12,7 +12,7 @@ import { useWalletClient as useWagmiWalletClient, useAccount, useConfig, useChai
|
|
|
12
12
|
import { getWalletClient, switchChain, getPublicClient } from '@wagmi/core';
|
|
13
13
|
import { getConnectorMeta } from './connectors';
|
|
14
14
|
import { getChainById } from './chains';
|
|
15
|
-
import { waitUntilDocumentVisible, pollForOutgoingTx, clearWalletConnectPendingState, isWalletConnectConnector, isMobileDevice, } from './walletConnectMobile';
|
|
15
|
+
import { waitUntilDocumentVisible, pollForOutgoingTx, clearWalletConnectPendingState, isWalletConnectConnector, isMobileDevice, isUserRejectionError, toUserRejectionError, } from './walletConnectMobile';
|
|
16
16
|
/**
|
|
17
17
|
* Hook to check if wallet is connected
|
|
18
18
|
*/
|
|
@@ -2057,7 +2057,7 @@ export function useSignAndSendTxn(provider) {
|
|
|
2057
2057
|
* ```
|
|
2058
2058
|
*/
|
|
2059
2059
|
export function useWaitForTxnReceipt(provider) {
|
|
2060
|
-
const waitForTxnReceipt = useCallback(async ({ hash, confirmations, timeout, }) => {
|
|
2060
|
+
const waitForTxnReceipt = useCallback(async ({ hash, confirmations, timeout, throwOnRevert = true, }) => {
|
|
2061
2061
|
if (!provider) {
|
|
2062
2062
|
throw new Error('Provider (publicClient) is required');
|
|
2063
2063
|
}
|
|
@@ -2080,9 +2080,18 @@ export function useWaitForTxnReceipt(provider) {
|
|
|
2080
2080
|
timeout: Math.min(20_000, remaining),
|
|
2081
2081
|
pollingInterval: 1_500,
|
|
2082
2082
|
});
|
|
2083
|
+
if (throwOnRevert &&
|
|
2084
|
+
(receipt.status === 'reverted' ||
|
|
2085
|
+
receipt.status === 0 ||
|
|
2086
|
+
receipt.status === '0x0')) {
|
|
2087
|
+
throw new Error('Transaction reverted');
|
|
2088
|
+
}
|
|
2083
2089
|
return receipt;
|
|
2084
2090
|
}
|
|
2085
2091
|
catch (error) {
|
|
2092
|
+
if (error instanceof Error && error.message === 'Transaction reverted') {
|
|
2093
|
+
throw error;
|
|
2094
|
+
}
|
|
2086
2095
|
lastError = error;
|
|
2087
2096
|
await waitUntilDocumentVisible();
|
|
2088
2097
|
await new Promise((resolve) => setTimeout(resolve, 1_000));
|
|
@@ -2096,6 +2105,9 @@ export function useWaitForTxnReceipt(provider) {
|
|
|
2096
2105
|
: new Error('Failed to wait for transaction receipt');
|
|
2097
2106
|
}
|
|
2098
2107
|
catch (error) {
|
|
2108
|
+
if (error instanceof Error && error.message === 'Transaction reverted') {
|
|
2109
|
+
throw error;
|
|
2110
|
+
}
|
|
2099
2111
|
if (error instanceof Error && error.message.startsWith('Failed to wait for transaction receipt')) {
|
|
2100
2112
|
throw error;
|
|
2101
2113
|
}
|
|
@@ -2523,7 +2535,12 @@ export function useWriteContract() {
|
|
|
2523
2535
|
// Matching without selector is still useful (from + to).
|
|
2524
2536
|
}
|
|
2525
2537
|
const cancelPoll = { cancelled: false };
|
|
2526
|
-
const sendPromise = sendWrite()
|
|
2538
|
+
const sendPromise = sendWrite().then((hash) => hash, (err) => {
|
|
2539
|
+
if (isUserRejectionError(err))
|
|
2540
|
+
throw toUserRejectionError(err);
|
|
2541
|
+
throw err;
|
|
2542
|
+
});
|
|
2543
|
+
// Success-only chain recovery when WC hash never arrives.
|
|
2527
2544
|
const pollPromise = pollForOutgoingTx({
|
|
2528
2545
|
publicClient,
|
|
2529
2546
|
from: fromAddress,
|
|
@@ -2532,12 +2549,11 @@ export function useWriteContract() {
|
|
|
2532
2549
|
value,
|
|
2533
2550
|
startBlock,
|
|
2534
2551
|
signal: cancelPoll,
|
|
2535
|
-
initialDelayMs:
|
|
2536
|
-
timeoutMs:
|
|
2552
|
+
initialDelayMs: 1_000,
|
|
2553
|
+
timeoutMs: 60_000,
|
|
2537
2554
|
});
|
|
2538
2555
|
try {
|
|
2539
2556
|
const hash = await Promise.race([sendPromise, pollPromise]);
|
|
2540
|
-
// Poll may win while WC is still hanging — ignore a late reject.
|
|
2541
2557
|
void sendPromise.then(() => undefined, () => undefined);
|
|
2542
2558
|
return hash;
|
|
2543
2559
|
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -16,4 +16,4 @@ export type { OnboardingUIComponentProps, OnboardingUIComponentRef } from './Onb
|
|
|
16
16
|
export { ALL_CHAINS, EVM_CHAINS, SOLANA_CHAINS, getChainById, getChainsByType, getDefaultChains, toCoreChain, type ChainData, } from './chains';
|
|
17
17
|
export { CONNECTORS, getConnectorMeta, isOAuthConnector, isWalletConnector, isAuthConnector, type ConnectorType, type ConnectorMeta, } from './connectors';
|
|
18
18
|
export { createWagmiConfig } from './wagmiConfig';
|
|
19
|
-
export { pollForOutgoingTx, clearWalletConnectPendingState, waitUntilDocumentVisible, isWalletConnectConnector, isMobileDevice, } from './walletConnectMobile';
|
|
19
|
+
export { pollForOutgoingTx, clearWalletConnectPendingState, waitUntilDocumentVisible, isWalletConnectConnector, isMobileDevice, forceResumeWalletConnectOnReturn, isUserRejectionError, toUserRejectionError, } from './walletConnectMobile';
|
package/dist/src/index.js
CHANGED
|
@@ -11,5 +11,5 @@ export { OnboardingUIComponent as OnboardingUI } from './OnboardingUI';
|
|
|
11
11
|
export { ALL_CHAINS, EVM_CHAINS, SOLANA_CHAINS, getChainById, getChainsByType, getDefaultChains, toCoreChain, } from './chains';
|
|
12
12
|
export { CONNECTORS, getConnectorMeta, isOAuthConnector, isWalletConnector, isAuthConnector, } from './connectors';
|
|
13
13
|
export { createWagmiConfig } from './wagmiConfig';
|
|
14
|
-
export { pollForOutgoingTx, clearWalletConnectPendingState, waitUntilDocumentVisible, isWalletConnectConnector, isMobileDevice, } from './walletConnectMobile';
|
|
14
|
+
export { pollForOutgoingTx, clearWalletConnectPendingState, waitUntilDocumentVisible, isWalletConnectConnector, isMobileDevice, forceResumeWalletConnectOnReturn, isUserRejectionError, toUserRejectionError, } from './walletConnectMobile';
|
|
15
15
|
//# sourceMappingURL=index.js.map
|
|
@@ -107,9 +107,12 @@ export declare function waitUntilDocumentVisible(): Promise<void>;
|
|
|
107
107
|
* (poll won while eth_sendTransaction is still hanging).
|
|
108
108
|
*/
|
|
109
109
|
export declare function clearWalletConnectPendingState(provider: any): void;
|
|
110
|
+
/** EIP-1193 4001 / WC 5000 (and common message shapes). */
|
|
111
|
+
export declare function isUserRejectionError(error: unknown): boolean;
|
|
112
|
+
export declare function toUserRejectionError(error?: unknown): Error;
|
|
110
113
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
114
|
+
* Success-only recovery: find an on-chain hash when WC never returns one.
|
|
115
|
+
* Does not infer reject (that is handled by relay resume + reject fallback).
|
|
113
116
|
*/
|
|
114
117
|
export declare function pollForOutgoingTx(params: {
|
|
115
118
|
publicClient: {
|
|
@@ -123,7 +126,6 @@ export declare function pollForOutgoingTx(params: {
|
|
|
123
126
|
};
|
|
124
127
|
from: string;
|
|
125
128
|
to: string;
|
|
126
|
-
/** Match tx.input prefix (e.g. 0x + 4-byte selector). */
|
|
127
129
|
dataPrefix?: string;
|
|
128
130
|
value?: bigint;
|
|
129
131
|
startBlock: bigint;
|
|
@@ -133,13 +135,15 @@ export declare function pollForOutgoingTx(params: {
|
|
|
133
135
|
timeoutMs?: number;
|
|
134
136
|
initialDelayMs?: number;
|
|
135
137
|
}): Promise<`0x${string}`>;
|
|
138
|
+
/** Time-bounded force-resume (must not hang on transportOpen). */
|
|
139
|
+
export declare function forceResumeWalletConnectOnReturn(provider: any, timeoutMs?: number): Promise<void>;
|
|
136
140
|
/**
|
|
137
141
|
* Patch the EIP-1193 provider so signing/tx requests resume the relay first.
|
|
138
142
|
* Covers wagmi hooks, viem walletClient, and direct provider.request calls.
|
|
139
143
|
*/
|
|
140
144
|
export declare function patchWalletConnectProviderForMobile(provider: any): void;
|
|
141
145
|
/**
|
|
142
|
-
* When the dapp tab is shown again
|
|
143
|
-
*
|
|
146
|
+
* When the dapp tab is shown again, restart the relay so pending
|
|
147
|
+
* approve/reject responses can be delivered (WalletConnect mobile linking).
|
|
144
148
|
*/
|
|
145
149
|
export declare function subscribeWalletConnectForegroundResume(provider: any): () => void;
|
|
@@ -569,19 +569,57 @@ export function clearWalletConnectPendingState(provider) {
|
|
|
569
569
|
// ignore
|
|
570
570
|
}
|
|
571
571
|
}
|
|
572
|
+
/** EIP-1193 4001 / WC 5000 (and common message shapes). */
|
|
573
|
+
export function isUserRejectionError(error) {
|
|
574
|
+
const walk = (err, depth = 0) => {
|
|
575
|
+
if (err == null || depth > 8)
|
|
576
|
+
return false;
|
|
577
|
+
if (typeof err === "string") {
|
|
578
|
+
return /user rejected|rejected by user|user denied|denied transaction|request rejected|cancelled by user/i.test(err);
|
|
579
|
+
}
|
|
580
|
+
if (typeof err !== "object")
|
|
581
|
+
return false;
|
|
582
|
+
const e = err;
|
|
583
|
+
if (e.code === 4001 || e.code === 5000 || e.code === "4001" || e.code === "ACTION_REJECTED") {
|
|
584
|
+
return true;
|
|
585
|
+
}
|
|
586
|
+
if (typeof e.name === "string" && /UserRejected/i.test(e.name))
|
|
587
|
+
return true;
|
|
588
|
+
const msg = `${e.message ?? ""} ${e.shortMessage ?? ""}`;
|
|
589
|
+
if (/user rejected|rejected by user|user denied|denied transaction|request rejected|user cancelled|user canceled/i.test(msg)) {
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
return walk(e.cause, depth + 1);
|
|
593
|
+
};
|
|
594
|
+
return walk(error);
|
|
595
|
+
}
|
|
596
|
+
export function toUserRejectionError(error) {
|
|
597
|
+
if (error instanceof Error && isUserRejectionError(error)) {
|
|
598
|
+
const err = new Error("User rejected the request");
|
|
599
|
+
err.code = 4001;
|
|
600
|
+
err.cause = error;
|
|
601
|
+
return err;
|
|
602
|
+
}
|
|
603
|
+
const err = new Error("User rejected the request");
|
|
604
|
+
err.code = 4001;
|
|
605
|
+
if (error !== undefined)
|
|
606
|
+
err.cause = error;
|
|
607
|
+
return err;
|
|
608
|
+
}
|
|
572
609
|
/**
|
|
573
|
-
*
|
|
574
|
-
*
|
|
610
|
+
* Success-only recovery: find an on-chain hash when WC never returns one.
|
|
611
|
+
* Does not infer reject (that is handled by relay resume + reject fallback).
|
|
575
612
|
*/
|
|
576
613
|
export async function pollForOutgoingTx(params) {
|
|
577
|
-
const { publicClient, from, to, dataPrefix, value, startBlock, signal, timeoutMs =
|
|
614
|
+
const { publicClient, from, to, dataPrefix, value, startBlock, signal, timeoutMs = 60_000, initialDelayMs = 1_000, } = params;
|
|
615
|
+
await waitUntilDocumentVisible();
|
|
616
|
+
if (signal.cancelled)
|
|
617
|
+
throw new Error("cancelled");
|
|
578
618
|
if (initialDelayMs > 0) {
|
|
579
619
|
await new Promise((r) => setTimeout(r, initialDelayMs));
|
|
580
620
|
}
|
|
581
|
-
if (signal.cancelled)
|
|
621
|
+
if (signal.cancelled)
|
|
582
622
|
throw new Error("cancelled");
|
|
583
|
-
}
|
|
584
|
-
await waitUntilDocumentVisible();
|
|
585
623
|
const fromLc = from.toLowerCase();
|
|
586
624
|
const toLc = to.toLowerCase();
|
|
587
625
|
const prefixLc = dataPrefix ? dataPrefix.toLowerCase() : undefined;
|
|
@@ -589,11 +627,7 @@ export async function pollForOutgoingTx(params) {
|
|
|
589
627
|
while (!signal.cancelled && Date.now() - started < timeoutMs) {
|
|
590
628
|
try {
|
|
591
629
|
const latest = await publicClient.getBlockNumber();
|
|
592
|
-
const fromBlock = startBlock > 0n
|
|
593
|
-
? startBlock
|
|
594
|
-
: latest > 12n
|
|
595
|
-
? latest - 12n
|
|
596
|
-
: 0n;
|
|
630
|
+
const fromBlock = startBlock > 0n ? startBlock : latest > 12n ? latest - 12n : 0n;
|
|
597
631
|
for (let b = fromBlock; b <= latest; b++) {
|
|
598
632
|
if (signal.cancelled)
|
|
599
633
|
break;
|
|
@@ -609,7 +643,8 @@ export async function pollForOutgoingTx(params) {
|
|
|
609
643
|
continue;
|
|
610
644
|
if (String(tx.to || "").toLowerCase() !== toLc)
|
|
611
645
|
continue;
|
|
612
|
-
if (value !== undefined &&
|
|
646
|
+
if (value !== undefined &&
|
|
647
|
+
BigInt(tx.value ?? 0) !== value) {
|
|
613
648
|
continue;
|
|
614
649
|
}
|
|
615
650
|
if (prefixLc) {
|
|
@@ -625,11 +660,83 @@ export async function pollForOutgoingTx(params) {
|
|
|
625
660
|
}
|
|
626
661
|
}
|
|
627
662
|
catch {
|
|
628
|
-
// RPC blip
|
|
663
|
+
// RPC blip
|
|
629
664
|
}
|
|
630
665
|
await new Promise((r) => setTimeout(r, 2_000));
|
|
631
666
|
}
|
|
632
|
-
|
|
667
|
+
// Stay pending until cancelled — reject UX is owned by the approval race.
|
|
668
|
+
if (signal.cancelled)
|
|
669
|
+
throw new Error("cancelled");
|
|
670
|
+
await new Promise(() => { });
|
|
671
|
+
throw new Error("cancelled");
|
|
672
|
+
}
|
|
673
|
+
/** Time-bounded force-resume (must not hang on transportOpen). */
|
|
674
|
+
export async function forceResumeWalletConnectOnReturn(provider, timeoutMs = 1_500) {
|
|
675
|
+
if (!provider)
|
|
676
|
+
return;
|
|
677
|
+
try {
|
|
678
|
+
provider[NEEDS_RESUME_FLAG] = true;
|
|
679
|
+
await Promise.race([
|
|
680
|
+
resumeWalletConnectRelayer(provider, { force: true }),
|
|
681
|
+
new Promise((resolve) => setTimeout(resolve, timeoutMs)),
|
|
682
|
+
]);
|
|
683
|
+
}
|
|
684
|
+
catch {
|
|
685
|
+
// best-effort
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
async function readPendingNonce(provider) {
|
|
689
|
+
try {
|
|
690
|
+
const accounts = provider?.accounts ||
|
|
691
|
+
provider?.session?.namespaces?.eip155?.accounts?.map((a) => a.includes(":") ? a.split(":").pop() : a) ||
|
|
692
|
+
[];
|
|
693
|
+
const address = accounts[0];
|
|
694
|
+
if (!address || typeof provider.request !== "function")
|
|
695
|
+
return null;
|
|
696
|
+
// Use unbound original if patched — readPendingNonce is called from
|
|
697
|
+
// inside the patch with the live provider; eth_getTransactionCount is
|
|
698
|
+
// not an approval method so the patch forwards it.
|
|
699
|
+
const hex = await provider.request({
|
|
700
|
+
method: "eth_getTransactionCount",
|
|
701
|
+
params: [address, "pending"],
|
|
702
|
+
});
|
|
703
|
+
return typeof hex === "string" ? parseInt(hex, 16) : Number(hex);
|
|
704
|
+
}
|
|
705
|
+
catch {
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Prefer WC delivering real approve/reject after return (docs: respondSessionRequest).
|
|
711
|
+
* If still pending with no nonce bump → EIP-1193-style user rejection.
|
|
712
|
+
* If nonce moved → do not fake reject (let success hash arrive via WC or poll).
|
|
713
|
+
*/
|
|
714
|
+
async function raceApprovalWithResumeAndRejectFallback(resultPromise, provider, startNonce) {
|
|
715
|
+
const normalizedResult = resultPromise.then((v) => v, (err) => {
|
|
716
|
+
if (isUserRejectionError(err))
|
|
717
|
+
throw toUserRejectionError(err);
|
|
718
|
+
throw err;
|
|
719
|
+
});
|
|
720
|
+
const rejectFallback = (async () => {
|
|
721
|
+
await waitUntilDocumentVisible();
|
|
722
|
+
await forceResumeWalletConnectOnReturn(provider, 1_500);
|
|
723
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
724
|
+
await forceResumeWalletConnectOnReturn(provider, 1_500);
|
|
725
|
+
// Window for MetaMask's real JSON-RPC reject/hash after resume.
|
|
726
|
+
await new Promise((r) => setTimeout(r, 5_000));
|
|
727
|
+
if (!hasPendingWalletConnectApproval(provider)) {
|
|
728
|
+
return await new Promise(() => { });
|
|
729
|
+
}
|
|
730
|
+
const currentNonce = await readPendingNonce(provider);
|
|
731
|
+
if (startNonce != null &&
|
|
732
|
+
currentNonce != null &&
|
|
733
|
+
currentNonce > startNonce) {
|
|
734
|
+
// Tx submitted — confirmation path owns this.
|
|
735
|
+
return await new Promise(() => { });
|
|
736
|
+
}
|
|
737
|
+
throw toUserRejectionError();
|
|
738
|
+
})();
|
|
739
|
+
return await Promise.race([normalizedResult, rejectFallback]);
|
|
633
740
|
}
|
|
634
741
|
function getRequestMethod(args) {
|
|
635
742
|
const payload = args[0];
|
|
@@ -661,7 +768,10 @@ export function patchWalletConnectProviderForMobile(provider) {
|
|
|
661
768
|
}
|
|
662
769
|
if (!isApproval && wasBackgrounded) {
|
|
663
770
|
try {
|
|
664
|
-
await
|
|
771
|
+
await Promise.race([
|
|
772
|
+
resumeWalletConnectRelayer(provider, { force: true }),
|
|
773
|
+
new Promise((resolve) => setTimeout(resolve, 1_500)),
|
|
774
|
+
]);
|
|
665
775
|
}
|
|
666
776
|
finally {
|
|
667
777
|
provider[NEEDS_RESUME_FLAG] = false;
|
|
@@ -669,10 +779,10 @@ export function patchWalletConnectProviderForMobile(provider) {
|
|
|
669
779
|
return originalRequest(...args);
|
|
670
780
|
}
|
|
671
781
|
let cancelDeeplinks;
|
|
782
|
+
let startNonce = null;
|
|
672
783
|
if (isApproval) {
|
|
673
784
|
provider[PENDING_FLAG] = (provider[PENDING_FLAG] || 0) + 1;
|
|
674
|
-
|
|
675
|
-
// during connect (no session yet).
|
|
785
|
+
startNonce = await readPendingNonce(provider);
|
|
676
786
|
if (hasActiveWalletConnectSession(provider)) {
|
|
677
787
|
hideWalletConnectModal(provider);
|
|
678
788
|
}
|
|
@@ -680,29 +790,24 @@ export function patchWalletConnectProviderForMobile(provider) {
|
|
|
680
790
|
restoreWalletConnectModal();
|
|
681
791
|
}
|
|
682
792
|
syncWalletConnectDappRedirect(provider);
|
|
683
|
-
// Mark before deeplink so a fast backgrounding still triggers force-resume.
|
|
684
793
|
provider[NEEDS_RESUME_FLAG] = true;
|
|
685
794
|
}
|
|
686
795
|
try {
|
|
687
|
-
// Never force-restart right before sending a new tx — that is what
|
|
688
|
-
// blocked the MetaMask popup on Create Proposal after 3.3.7.
|
|
689
796
|
await Promise.race([
|
|
690
797
|
resumeWalletConnectRelayer(provider, { force: false }),
|
|
691
798
|
new Promise((resolve) => setTimeout(resolve, 1000)),
|
|
692
799
|
]);
|
|
693
800
|
const resultPromise = originalRequest(...args);
|
|
694
801
|
if (isApproval) {
|
|
695
|
-
// Do NOT auto-deeplink when a session already exists.
|
|
696
|
-
// WC ethereum-provider already opens the peer wallet; our extra
|
|
697
|
-
// metamask:// calls queue iOS "Open in MetaMask?" dialogs that stay
|
|
698
|
-
// on screen after the tx is confirmed (JS cannot dismiss them).
|
|
699
|
-
// Connect flow (no session) may still use a single scheduled open.
|
|
700
802
|
if (!hasActiveWalletConnectSession(provider)) {
|
|
701
803
|
cancelDeeplinks = scheduleOpenConnectedWalletApp(provider);
|
|
702
804
|
}
|
|
703
805
|
else {
|
|
704
806
|
hideWalletConnectModal(provider);
|
|
705
807
|
}
|
|
808
|
+
if (isMobileDevice()) {
|
|
809
|
+
return await raceApprovalWithResumeAndRejectFallback(resultPromise, provider, startNonce);
|
|
810
|
+
}
|
|
706
811
|
}
|
|
707
812
|
return await resultPromise;
|
|
708
813
|
}
|
|
@@ -711,7 +816,6 @@ export function patchWalletConnectProviderForMobile(provider) {
|
|
|
711
816
|
if (isApproval) {
|
|
712
817
|
provider[PENDING_FLAG] = Math.max(0, (provider[PENDING_FLAG] || 1) - 1);
|
|
713
818
|
provider.__abstraxnWcDeeplinkOpened = false;
|
|
714
|
-
// Close picker that may have been left open after approve/reject.
|
|
715
819
|
hideWalletConnectModal(provider);
|
|
716
820
|
if (!hasPendingWalletConnectApproval(provider)) {
|
|
717
821
|
provider[NEEDS_RESUME_FLAG] = false;
|
|
@@ -721,8 +825,8 @@ export function patchWalletConnectProviderForMobile(provider) {
|
|
|
721
825
|
};
|
|
722
826
|
}
|
|
723
827
|
/**
|
|
724
|
-
* When the dapp tab is shown again
|
|
725
|
-
*
|
|
828
|
+
* When the dapp tab is shown again, restart the relay so pending
|
|
829
|
+
* approve/reject responses can be delivered (WalletConnect mobile linking).
|
|
726
830
|
*/
|
|
727
831
|
export function subscribeWalletConnectForegroundResume(provider) {
|
|
728
832
|
if (typeof window === "undefined" || !provider)
|
|
@@ -732,35 +836,32 @@ export function subscribeWalletConnectForegroundResume(provider) {
|
|
|
732
836
|
timers.splice(0).forEach((t) => clearTimeout(t));
|
|
733
837
|
const pending = hasPendingWalletConnectApproval(provider);
|
|
734
838
|
const needsResume = pending || !!provider[NEEDS_RESUME_FLAG];
|
|
735
|
-
// Do not restart after connect-only backgrounding — that broke the next
|
|
736
|
-
// session_request so MetaMask never opened for Create Proposal.
|
|
737
839
|
if (!needsResume) {
|
|
738
840
|
clearWalletReturnIfSameDocument();
|
|
739
841
|
return;
|
|
740
842
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
void resumeWalletConnectRelayer(provider, { force: true }).then(() => {
|
|
751
|
-
if (!hasPendingWalletConnectApproval(provider)) {
|
|
752
|
-
provider[NEEDS_RESUME_FLAG] = false;
|
|
753
|
-
hideWalletConnectModal(provider);
|
|
754
|
-
}
|
|
755
|
-
});
|
|
756
|
-
// Do not restoreWalletConnectModal here — that reopens "All Wallets".
|
|
757
|
-
if (!hasActiveWalletConnectSession(provider)) {
|
|
758
|
-
restoreWalletConnectModal();
|
|
759
|
-
}
|
|
760
|
-
else {
|
|
843
|
+
const run = () => {
|
|
844
|
+
if (!hasPendingWalletConnectApproval(provider) &&
|
|
845
|
+
!provider[NEEDS_RESUME_FLAG]) {
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
clearWalletReturnIfSameDocument();
|
|
849
|
+
void forceResumeWalletConnectOnReturn(provider, 1_500).then(() => {
|
|
850
|
+
if (!hasPendingWalletConnectApproval(provider)) {
|
|
851
|
+
provider[NEEDS_RESUME_FLAG] = false;
|
|
761
852
|
hideWalletConnectModal(provider);
|
|
762
853
|
}
|
|
763
|
-
}
|
|
854
|
+
});
|
|
855
|
+
if (!hasActiveWalletConnectSession(provider)) {
|
|
856
|
+
restoreWalletConnectModal();
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
hideWalletConnectModal(provider);
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
run();
|
|
863
|
+
[800, 2_000].forEach((ms) => {
|
|
864
|
+
timers.push(setTimeout(run, ms));
|
|
764
865
|
});
|
|
765
866
|
};
|
|
766
867
|
const onVisibility = () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abstraxn/signer-react",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.10",
|
|
4
4
|
"description": "React SDK for Abstraxn Wallet - React components, hooks, and providers for seamless Web3 wallet integration",
|
|
5
5
|
"main": "./dist/src/index.js",
|
|
6
6
|
"module": "./dist/src/index.js",
|