@silentswap/react 0.1.1 → 0.1.3
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.
|
@@ -35,9 +35,11 @@ export function useOrderSigning(walletClient, connector, client, setCurrentStep,
|
|
|
35
35
|
if (!connector) {
|
|
36
36
|
throw new Error('Connector required for chain switching');
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
// ensureChain returns a fresh walletClient bound to the target chain —
|
|
39
|
+
// critical for WalletConnect where the old client's chain scope gets silently dropped.
|
|
40
|
+
const signingClient = isDepositingDirectly
|
|
41
|
+
? await ensureChain(NI_CHAIN_ID_AVALANCHE, walletClient, connector, { required: false })
|
|
42
|
+
: walletClient;
|
|
41
43
|
return Promise.all(authorizations.map(async (auth) => ({
|
|
42
44
|
...auth,
|
|
43
45
|
signature: await (async () => {
|
|
@@ -45,7 +47,7 @@ export function useOrderSigning(walletClient, connector, client, setCurrentStep,
|
|
|
45
47
|
if (auth.type === 'eip3009_deposit') {
|
|
46
48
|
if (isDepositingDirectly) {
|
|
47
49
|
// Sign EIP-712 typed data for direct deposit
|
|
48
|
-
return await
|
|
50
|
+
return await signingClient.signTypedData(auth.eip712);
|
|
49
51
|
}
|
|
50
52
|
else {
|
|
51
53
|
// Will be deposited through proxy, no signature needed
|
|
@@ -83,18 +85,20 @@ export function useOrderSigning(walletClient, connector, client, setCurrentStep,
|
|
|
83
85
|
throw new Error('Facilitator group required for order creation');
|
|
84
86
|
}
|
|
85
87
|
// Switch to Ethereum for order signing (orders are signed on Ethereum mainnet)
|
|
88
|
+
// ensureChain returns a fresh walletClient bound to the target chain —
|
|
89
|
+
// critical for WalletConnect where the old client's chain scope gets silently dropped.
|
|
86
90
|
setCurrentStep('Preparing order signature');
|
|
87
91
|
onStatus?.('Preparing order signature');
|
|
88
|
-
await ensureChain(1, walletClient, connector
|
|
92
|
+
const signingClient = await ensureChain(1, walletClient, connector, { required: false });
|
|
89
93
|
// Create EIP-712 document for order
|
|
90
94
|
const orderDoc = quoteResponseToEip712Document(quoteResponse);
|
|
91
95
|
// Sign the order's EIP-712 document
|
|
92
96
|
// Note: viem's signTypedData may normalize the domain.chainId to match the wallet client's
|
|
93
97
|
// chain configuration, which can result in chainId being a BigInt instead of a number.
|
|
94
98
|
// This happens because viem uses the wallet's chain configuration internally.
|
|
95
|
-
const orderSignature = await
|
|
99
|
+
const orderSignature = await signingClient.signTypedData({
|
|
96
100
|
...orderDoc,
|
|
97
|
-
account:
|
|
101
|
+
account: signingClient.account,
|
|
98
102
|
});
|
|
99
103
|
// Approve proxy authorizations from facilitators
|
|
100
104
|
const facilitatorReplies = await effectiveGroup.approveProxyAuthorizations(quoteResponse.facilitators, {
|
|
@@ -94,7 +94,10 @@ export function useWallet({ client, address, auth, walletClient, connector, allD
|
|
|
94
94
|
throw new Error('Connector required for chain switching');
|
|
95
95
|
}
|
|
96
96
|
// Ensure we're on Ethereum mainnet for entropy generation (asked core devs about this in tg)
|
|
97
|
-
|
|
97
|
+
// ensureChain returns a fresh walletClient bound to the target chain after switching.
|
|
98
|
+
// Critical for WalletConnect: the old walletClient's chain scope doesn't match after
|
|
99
|
+
// a switch, so signing requests get silently dropped by the mobile wallet.
|
|
100
|
+
const signingClient = await ensureChain(1, walletClient, connector, { required: false });
|
|
98
101
|
// Create EIP-712 document for wallet generation
|
|
99
102
|
const eip712Doc = createEip712DocForWalletGeneration(`eip155:43114:${address}`, // Gateway contract scope (Avalanche)
|
|
100
103
|
auth.secretToken);
|
|
@@ -102,10 +105,11 @@ export function useWallet({ client, address, auth, walletClient, connector, allD
|
|
|
102
105
|
if (eip712Doc.domain && typeof eip712Doc.domain.chainId === 'number') {
|
|
103
106
|
eip712Doc.domain.chainId = BigInt(eip712Doc.domain.chainId);
|
|
104
107
|
}
|
|
105
|
-
// Sign the document to generate entropy
|
|
106
|
-
|
|
108
|
+
// Sign the document to generate entropy — use the fresh signingClient, not
|
|
109
|
+
// the closure's walletClient which may be scoped to the pre-switch chain.
|
|
110
|
+
const signature = await signingClient.signTypedData({
|
|
107
111
|
...eip712Doc,
|
|
108
|
-
account:
|
|
112
|
+
account: signingClient.account,
|
|
109
113
|
});
|
|
110
114
|
return hexToBytes(signature);
|
|
111
115
|
}, [auth, walletClient, connector, address]);
|
|
@@ -176,7 +180,7 @@ export function useWallet({ client, address, auth, walletClient, connector, allD
|
|
|
176
180
|
isGeneratingRef.current = false;
|
|
177
181
|
setIsLoading(false);
|
|
178
182
|
}
|
|
179
|
-
}, [normalizedAddress, getCachedWallet,
|
|
183
|
+
}, [normalizedAddress, getCachedWallet, generateEntropy, allDeposits, client.s0xGatewayAddress]);
|
|
180
184
|
/**
|
|
181
185
|
* Clear cached wallet
|
|
182
186
|
*/
|
|
@@ -194,6 +198,13 @@ export function useWallet({ client, address, auth, walletClient, connector, allD
|
|
|
194
198
|
isGeneratingRef.current = false;
|
|
195
199
|
await generateWallet();
|
|
196
200
|
}, [clearWallet, generateWallet]);
|
|
201
|
+
// When walletClient or connector changes (e.g. WalletConnect chain switch causes
|
|
202
|
+
// wagmi to recreate the walletClient), reset the generation guard. Any in-flight
|
|
203
|
+
// generation using stale WalletConnect references will hang on signTypedData,
|
|
204
|
+
// permanently blocking future calls.
|
|
205
|
+
useEffect(() => {
|
|
206
|
+
isGeneratingRef.current = false;
|
|
207
|
+
}, [walletClient, connector]);
|
|
197
208
|
// Clear wallet when address changes (e.g. user switched from MetaMask to Phantom)
|
|
198
209
|
const prevAddressRef = useRef(normalizedAddress);
|
|
199
210
|
useEffect(() => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
export type PlatformHealthStatus = 'ON' | 'ONLINE' | 'PAUSED' | 'DEPOSITS_PAUSED' | 'OFF' | 'MAINTENANCE' | 'UNKNOWN';
|
|
3
|
-
export declare const MAX_DEPOSIT_USD = 25000;
|
|
4
3
|
export type PlatformHealthContextType = {
|
|
5
4
|
platformHealth: PlatformHealthStatus | null;
|
|
6
5
|
maximumDepositUusdc: string | undefined;
|
|
@@ -14,6 +13,8 @@ export type PlatformHealthContextType = {
|
|
|
14
13
|
storage: Record<string, string> | undefined;
|
|
15
14
|
formDisabled: boolean;
|
|
16
15
|
trackingDisabled: boolean;
|
|
16
|
+
/** Effective maximum deposit in USD (min of admin cap and platform API cap), or null if no cap. */
|
|
17
|
+
effectiveMaxDepositUsd: number | null;
|
|
17
18
|
validateDepositAmount: (usdAmount: string | number) => {
|
|
18
19
|
valid: boolean;
|
|
19
20
|
error?: string;
|
|
@@ -43,13 +44,19 @@ export type PlatformHealthProviderProps = {
|
|
|
43
44
|
* If not provided, trackingDisabled will always be false in the context
|
|
44
45
|
*/
|
|
45
46
|
onTrackingDisabledChange?: (disabled: boolean) => void;
|
|
47
|
+
/**
|
|
48
|
+
* Optional maximum deposit amount in USD, typically fetched from admin dashboard settings.
|
|
49
|
+
* If not provided (undefined), no frontend cap is enforced — only the platform
|
|
50
|
+
* API's own maximumDepositUusdc limit applies.
|
|
51
|
+
*/
|
|
52
|
+
maxDepositUsd?: number;
|
|
46
53
|
};
|
|
47
54
|
/**
|
|
48
55
|
* Provider that monitors platform health from SilentSwapContext (which calls useStatus
|
|
49
56
|
* once with proId) and provides validation functions for deposit amounts, output limits,
|
|
50
57
|
* and service fee rates.
|
|
51
58
|
*/
|
|
52
|
-
export declare function PlatformHealthProvider({ children, onFormDisabledChange, onTrackingDisabledChange, }: PlatformHealthProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
59
|
+
export declare function PlatformHealthProvider({ children, onFormDisabledChange, onTrackingDisabledChange, maxDepositUsd, }: PlatformHealthProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
53
60
|
/**
|
|
54
61
|
* Hook to access platform health context
|
|
55
62
|
*/
|
|
@@ -3,14 +3,13 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import React, { createContext, useContext, useEffect, useMemo, useCallback } from 'react';
|
|
4
4
|
import { useSilentSwap } from '../contexts/SilentSwapContext.js';
|
|
5
5
|
import { BigNumber } from 'bignumber.js';
|
|
6
|
-
export const MAX_DEPOSIT_USD = 25000;
|
|
7
6
|
const PlatformHealthContext = createContext(undefined);
|
|
8
7
|
/**
|
|
9
8
|
* Provider that monitors platform health from SilentSwapContext (which calls useStatus
|
|
10
9
|
* once with proId) and provides validation functions for deposit amounts, output limits,
|
|
11
10
|
* and service fee rates.
|
|
12
11
|
*/
|
|
13
|
-
export function PlatformHealthProvider({ children, onFormDisabledChange, onTrackingDisabledChange, }) {
|
|
12
|
+
export function PlatformHealthProvider({ children, onFormDisabledChange, onTrackingDisabledChange, maxDepositUsd, }) {
|
|
14
13
|
// Consume status data from parent SilentSwapContext instead of calling useStatus again
|
|
15
14
|
const { status } = useSilentSwap();
|
|
16
15
|
const { platformHealth: statusPlatformHealth, maximumDepositUusdc, minimumDepositUusdc, outputLimit, serviceFeeRate, overheadUsd, identity, volume, liquidity, storage, } = status;
|
|
@@ -98,6 +97,13 @@ export function PlatformHealthProvider({ children, onFormDisabledChange, onTrack
|
|
|
98
97
|
return 0.01;
|
|
99
98
|
return rate;
|
|
100
99
|
}, [serviceFeeRate]);
|
|
100
|
+
// Compute effective max deposit: min of admin cap and platform API cap, or null if neither is set
|
|
101
|
+
const effectiveMaxDepositUsd = useMemo(() => {
|
|
102
|
+
const platformMax = getMaximumDepositUsd();
|
|
103
|
+
if (maxDepositUsd != null && platformMax != null)
|
|
104
|
+
return Math.min(maxDepositUsd, platformMax);
|
|
105
|
+
return maxDepositUsd ?? platformMax ?? null;
|
|
106
|
+
}, [maxDepositUsd, getMaximumDepositUsd]);
|
|
101
107
|
// Validate deposit amount against min/max limits
|
|
102
108
|
const validateDepositAmount = useCallback((usdAmount) => {
|
|
103
109
|
const amount = typeof usdAmount === 'string' ? parseFloat(usdAmount) : usdAmount;
|
|
@@ -105,15 +111,14 @@ export function PlatformHealthProvider({ children, onFormDisabledChange, onTrack
|
|
|
105
111
|
return { valid: false, error: 'Amount must be greater than zero' };
|
|
106
112
|
}
|
|
107
113
|
const minUsd = getMinimumDepositUsd();
|
|
108
|
-
const maxUsd = Math.min(MAX_DEPOSIT_USD, getMaximumDepositUsd() ?? MAX_DEPOSIT_USD);
|
|
109
114
|
if (minUsd !== null && amount < minUsd) {
|
|
110
115
|
return { valid: false, error: `Minimum value is $${minUsd.toFixed(2)}` };
|
|
111
116
|
}
|
|
112
|
-
if (
|
|
113
|
-
return { valid: false, error: `Maximum value is $${
|
|
117
|
+
if (effectiveMaxDepositUsd !== null && amount > effectiveMaxDepositUsd) {
|
|
118
|
+
return { valid: false, error: `Maximum value is $${effectiveMaxDepositUsd.toFixed(2)}` };
|
|
114
119
|
}
|
|
115
120
|
return { valid: true };
|
|
116
|
-
}, [getMinimumDepositUsd,
|
|
121
|
+
}, [getMinimumDepositUsd, effectiveMaxDepositUsd]);
|
|
117
122
|
// Validate output count against limit
|
|
118
123
|
const validateOutputCount = useCallback((count) => {
|
|
119
124
|
if (outputLimit === null || outputLimit === undefined) {
|
|
@@ -144,6 +149,7 @@ export function PlatformHealthProvider({ children, onFormDisabledChange, onTrack
|
|
|
144
149
|
storage,
|
|
145
150
|
formDisabled,
|
|
146
151
|
trackingDisabled,
|
|
152
|
+
effectiveMaxDepositUsd,
|
|
147
153
|
validateDepositAmount,
|
|
148
154
|
validateOutputCount,
|
|
149
155
|
getMinimumDepositUsd,
|
|
@@ -162,6 +168,7 @@ export function PlatformHealthProvider({ children, onFormDisabledChange, onTrack
|
|
|
162
168
|
storage,
|
|
163
169
|
formDisabled,
|
|
164
170
|
trackingDisabled,
|
|
171
|
+
effectiveMaxDepositUsd,
|
|
165
172
|
validateDepositAmount,
|
|
166
173
|
validateOutputCount,
|
|
167
174
|
getMinimumDepositUsd,
|
package/dist/index.d.ts
CHANGED
|
@@ -29,7 +29,6 @@ export { useStatus } from './hooks/useStatus.js';
|
|
|
29
29
|
export type { StatusResponse, UseStatusOptions } from './hooks/useStatus.js';
|
|
30
30
|
export { PlatformHealthProvider, usePlatformHealthContext } from './hooks/usePlatformHealth.js';
|
|
31
31
|
export type { PlatformHealthStatus, PlatformHealthContextType, PlatformHealthProviderProps, } from './hooks/usePlatformHealth.js';
|
|
32
|
-
export { MAX_DEPOSIT_USD } from './hooks/usePlatformHealth.js';
|
|
33
32
|
export { PlatformHealthMonitor, usePlatformHealthMonitor, } from './hooks/usePlatformHealthMonitor.js';
|
|
34
33
|
export type { PlatformHealthMonitorProps } from './hooks/usePlatformHealthMonitor.js';
|
|
35
34
|
export { useHiddenSwapFees } from './hooks/useHiddenSwapFees.js';
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,6 @@ export { useSwap, getSourceAssetCaip19, X_RANGE_SLIDER_MIN_GAP, OUTPUT_LIMIT, DE
|
|
|
19
19
|
export { useEgressEstimates } from './hooks/useEgressEstimates.js';
|
|
20
20
|
export { useStatus } from './hooks/useStatus.js';
|
|
21
21
|
export { PlatformHealthProvider, usePlatformHealthContext } from './hooks/usePlatformHealth.js';
|
|
22
|
-
export { MAX_DEPOSIT_USD } from './hooks/usePlatformHealth.js';
|
|
23
22
|
export { PlatformHealthMonitor, usePlatformHealthMonitor, } from './hooks/usePlatformHealthMonitor.js';
|
|
24
23
|
export { useHiddenSwapFees } from './hooks/useHiddenSwapFees.js';
|
|
25
24
|
export { useSlippageUsd } from './hooks/useSlippageUsd.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silentswap/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@bigmi/core": "^0.6.5",
|
|
26
26
|
"@ensdomains/ensjs": "^4.2.0",
|
|
27
|
-
"@silentswap/sdk": "0.1.
|
|
28
|
-
"@silentswap/ui-kit": "0.1.
|
|
27
|
+
"@silentswap/sdk": "0.1.3",
|
|
28
|
+
"@silentswap/ui-kit": "0.1.3",
|
|
29
29
|
"@solana/codecs-strings": "^5.1.0",
|
|
30
30
|
"@solana/kit": "^5.1.0",
|
|
31
31
|
"@solana/rpc": "^5.1.0",
|