@ninsei-labs/sdk 0.39.3 → 0.40.0
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 +55 -0
- package/engine/atomic/dleq2.js +86 -111
- package/engine/atomic/halfenc.js +58 -72
- package/engine/atomic/halves.js +31 -53
- package/engine/atomic/order-client.js +15 -16
- package/engine/atomic/order.js +44 -62
- package/engine/atomic/orderContext.js +26 -50
- package/engine/atomic/orderHalfCommit.js +17 -18
- package/engine/core/chainSource.js +54 -69
- package/engine/core/clock.js +11 -12
- package/engine/core/config.js +561 -451
- package/engine/core/finality.js +34 -53
- package/engine/core/format.js +35 -36
- package/engine/core/preSignGuards.js +109 -117
- package/engine/core/rfqSource.js +57 -75
- package/engine/core/sellWindow.js +23 -24
- package/engine/core/store.js +20 -21
- package/engine/core/swap.js +242 -243
- package/engine/evm/amounts.js +50 -51
- package/engine/evm/asyncExec.js +577 -0
- package/engine/evm/asyncLegs.js +308 -0
- package/engine/evm/asyncRoute.js +179 -0
- package/engine/evm/auth.js +41 -48
- package/engine/evm/claimGas.js +28 -47
- package/engine/evm/depositor.js +39 -43
- package/engine/evm/dex.js +266 -267
- package/engine/evm/escrow.js +113 -129
- package/engine/evm/factory.js +71 -77
- package/engine/evm/fees.js +41 -42
- package/engine/evm/funding.js +160 -162
- package/engine/evm/gasReserve.js +67 -36
- package/engine/evm/index.js +46 -53
- package/engine/evm/injected.js +34 -42
- package/engine/evm/permit.js +129 -56
- package/engine/evm/prices.js +30 -45
- package/engine/evm/session.js +188 -189
- package/engine/mock/chain.js +17 -18
- package/engine/monero/address.js +33 -48
- package/engine/monero/halvesSweep.js +25 -43
- package/engine/monero/node.js +14 -15
- package/engine/monero/scan.js +82 -95
- package/engine/monero/swapKeys.js +30 -33
- package/engine/monero/unlock.js +17 -20
- package/engine/monero/wallet.js +32 -42
- package/engine/recovery/recoveryFile.js +154 -161
- package/engine/recovery/restore.js +50 -61
- package/engine/sdk/bridge.js +244 -234
- package/engine/ui/dom.js +4 -5
- package/engine/ui/walletModal.js +20 -31
- package/index.d.ts +8 -0
- package/package.json +1 -1
- package/src/adapters/evm-wallet.mjs +16 -0
- package/src/adapters/monero-wallet.mjs +1 -1
- package/src/adapters/monero.mjs +1 -1
- package/src/adapters/node-test-evm-wallet.mjs +20 -8
- package/src/config.mjs +1 -1
- package/src/engine.mjs +4 -0
- package/src/legs/cow-spec.mjs +254 -0
- package/src/legs/cow.mjs +315 -0
- package/src/legs/evm.mjs +86 -2
- package/src/legs/kyber-spec.mjs +265 -0
- package/src/legs/kyber.mjs +425 -0
- package/src/legs/shape.mjs +35 -0
- package/src/legs/uniswaprelay-spec.mjs +541 -0
- package/src/legs/uniswaprelay.mjs +422 -0
- package/src/legs/uniswapx-spec.mjs +329 -0
- package/src/legs/uniswapx.mjs +362 -0
- package/src/quotes.mjs +1 -1
- package/src/swaps.mjs +1 -1
package/engine/evm/gasReserve.js
CHANGED
|
@@ -1,55 +1,74 @@
|
|
|
1
1
|
// GENERATED FILE - a byte-for-byte copy of the engine module www/js/evm/gasReserve.js for the SDK package.
|
|
2
|
-
// Edit the source under www/js
|
|
3
|
-
// tools/check-sdk-engine.mjs reddens on any drift, so a stale copy cannot ship silently.
|
|
2
|
+
// Edit the source under www/js and regenerate the mirror; a drift guard reddens on any difference.
|
|
4
3
|
// Everything below this header is identical to the source.
|
|
5
4
|
|
|
6
|
-
//
|
|
5
|
+
// THE BUYER GAS RESERVE FOR ORDER ACTIONS: THE READINESS MARK AND A POSSIBLE REFUND.
|
|
7
6
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
7
|
+
// THE POINT. In a direct swap the person deposits into the escrow, and after the XMR arrives calls markReady itself
|
|
8
|
+
// (when the XMR is confirmed) or refund (when the swap did not happen). Both calls cost gas in the network
|
|
9
|
+
// NATIVE coin, and a person coming from USDC has no native of their own. So BEFORE the quote it is decided HOW MUCH
|
|
10
|
+
// NATIVE to leave for those two calls; the decision is shown both in ETH and in dollars, and enters the price breakdown as a line.
|
|
12
11
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
12
|
+
// WHY PURE FUNCTIONS. The decision costs money and must be checked without a network
|
|
13
|
+
// and computed by THE SAME code on screen and in the run. Only reading the gas price touches the network - the
|
|
14
|
+
// caller supplies it (www/js/evm/prices.js puts gasPriceWei into the live prices, the screen passes it here).
|
|
16
15
|
//
|
|
17
|
-
//
|
|
18
|
-
// (
|
|
19
|
-
//
|
|
20
|
-
//
|
|
16
|
+
// THE NUMBERS ARE NOT INVENTED. The gas limits are the same ones OUR OWN code sends both transactions with
|
|
17
|
+
// (the swap engine is now in the package: sdk/src/swap-flow.mjs - markReadyOrder - gas 120000, refundOrder - gas
|
|
18
|
+
// 250000). The check compares both constants against the lines of that file, so
|
|
19
|
+
// editing one place without the other reddens the run - exactly as done for the claim gas in rfq/reverseGas.mjs.
|
|
21
20
|
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
21
|
+
// WHY THE RESERVE IS FIXED BEFORE THE QUOTE. The order `amount` is part of the SIGNED quote, and the reserve
|
|
22
|
+
// decision changes the final deposit amount; so it is made BEFORE the quote request and not recomputed afterwards.
|
|
23
|
+
// The screen puts the ready plan into the form state (www/js/ui/views/swapForm.js), and the signing screen uses the
|
|
24
|
+
// same fixed plan - a second recomputation would diverge from the first.
|
|
26
25
|
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
26
|
+
// THE DEPOSIT'S GAS COMES FROM THE FUNDING CODE, NOT FROM A SECOND NUMBER. `orderGasReservePlan` below can
|
|
27
|
+
// include the escrow deposit (createOrderAndFund, evm/funding.js: GAS_CREATE_ORDER_AND_FUND): on the path where
|
|
28
|
+
// the wallet holds no native of its own the deposit is paid AFTER the swap, so its gas must be part of the
|
|
29
|
+
// reserve that decides whether the wallet can afford the path. The constant is imported, not copied.
|
|
30
|
+
import { GAS_CREATE_ORDER_AND_FUND } from "./funding.js";
|
|
31
|
+
|
|
32
|
+
// THE GAS LIMITS ARE FROM OUR OWN CODE. Source lines: sdk/src/swap-flow.mjs (gas: 120_000n at the mark and
|
|
33
|
+
// gas: 250_000n at the refund). A limit set too low is a refusal already after the half is revealed; unused
|
|
34
|
+
// gas in the limit is not charged, so the reserve is taken with a margin.
|
|
30
35
|
export const ORDER_READY_GAS_LIMIT = 120_000n; // markReady - sdk/src/swap-flow.mjs markReadyOrder
|
|
31
36
|
export const ORDER_REFUND_GAS_LIMIT = 250_000n; // refund - sdk/src/swap-flow.mjs refundOrder
|
|
32
37
|
export const ORDER_GAS_LIMIT = ORDER_READY_GAS_LIMIT + ORDER_REFUND_GAS_LIMIT;
|
|
38
|
+
// THE ESCROW DEPOSIT'S OWN GAS LIMIT - the same number funding sends createOrderAndFund with. It is NOT folded
|
|
39
|
+
// into ORDER_GAS_LIMIT (that constant's meaning - the mark and the refund - stays intact for the checks that pin
|
|
40
|
+
// it); it is added ON TOP when the path pays the deposit separately (the no-own-native path), see
|
|
41
|
+
// orderGasReserveWei's `depositGasLimit`.
|
|
42
|
+
export const ORDER_DEPOSIT_GAS_LIMIT = GAS_CREATE_ORDER_AND_FUND;
|
|
33
43
|
|
|
34
44
|
const toBig = (v) => {
|
|
35
45
|
if (v === null || v === undefined || v === "") return null;
|
|
36
46
|
try { return BigInt(typeof v === "bigint" ? v : String(v)); } catch { return null; }
|
|
37
47
|
};
|
|
38
48
|
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
export function orderGasReserveWei({ gasPriceWei, readyGasLimit = ORDER_READY_GAS_LIMIT, refundGasLimit = ORDER_REFUND_GAS_LIMIT } = {}) {
|
|
49
|
+
// HOW MANY WEI IS NEEDED FOR BOTH CALLS. The gas price comes from the chain, the limits are ours. A zero price
|
|
50
|
+
// and an unreadable number mean "not measured", and this is NOT zero gas: an unknown requirement must be named,
|
|
51
|
+
// not passed off as zero (the same rule as for the claim gas: rfq/reverseGas.mjs).
|
|
52
|
+
export function orderGasReserveWei({ gasPriceWei, readyGasLimit = ORDER_READY_GAS_LIMIT, refundGasLimit = ORDER_REFUND_GAS_LIMIT, depositGasLimit = 0n, extraFeeWei = 0n } = {}) {
|
|
43
53
|
const gp = toBig(gasPriceWei);
|
|
44
54
|
if (gp === null || gp <= 0n) return null;
|
|
45
55
|
const ready = toBig(readyGasLimit);
|
|
46
56
|
const refund = toBig(refundGasLimit);
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
// THE DEPOSIT IS OPT-IN AND DEFAULTS TO ZERO: the mark+refund reserve is unchanged for every existing caller
|
|
58
|
+
// (and the checks that pin 370 000 gas). A no-own-native path passes ORDER_DEPOSIT_GAS_LIMIT here so the reserve
|
|
59
|
+
// it is judged against includes the deposit it will pay after the swap. A negative deposit is a defect -> null.
|
|
60
|
+
const deposit = toBig(depositGasLimit);
|
|
61
|
+
// THE SECOND LEG'S EXTRA FEE (a composed route) IS ADDED ON TOP, and it is a FLAT wei amount, not gas: the
|
|
62
|
+
// conversion WETH->native costs the person that fee, so the native the path must cover is larger by it. Defaults to
|
|
63
|
+
// zero so every existing caller (and the checks pinning the mark+refund reserve) is unchanged.
|
|
64
|
+
const extra = toBig(extraFeeWei);
|
|
65
|
+
if (ready === null || refund === null || deposit === null || extra === null) return null;
|
|
66
|
+
if (ready <= 0n || refund <= 0n || deposit < 0n || extra < 0n) return null;
|
|
67
|
+
return gp * (ready + refund + deposit) + extra;
|
|
49
68
|
}
|
|
50
69
|
|
|
51
|
-
//
|
|
52
|
-
//
|
|
70
|
+
// DISPLAY IN BOTH UNITS. A person coming from USDC has no sense of ETH scale, so the reserve is shown both
|
|
71
|
+
// in ETH and in dollars. The dollar is an estimate at the live native rate; no rate - no estimate (null), not a made-up one.
|
|
53
72
|
export function gasReserveDisplay({ reserveWei, nativeUsd, decimals = 18 } = {}) {
|
|
54
73
|
const w = toBig(reserveWei);
|
|
55
74
|
if (w === null || w <= 0n) return null;
|
|
@@ -58,9 +77,9 @@ export function gasReserveDisplay({ reserveWei, nativeUsd, decimals = 18 } = {})
|
|
|
58
77
|
return { native, usd };
|
|
59
78
|
}
|
|
60
79
|
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
80
|
+
// DECISION BY THE CHECKBOX. The checkbox is NEEDED only when one own native is NOT ENOUGH for both calls; with enough
|
|
81
|
+
// ETH it is not shown at all - the person pays with their own gas, and there is nothing to ask of them. An unreadable
|
|
82
|
+
// native balance is a separate state: we offer the reserve (better to offer than stay silent about the shortfall), and this is named by a field.
|
|
64
83
|
export function gasReserveChoice({ nativeBalanceWei, reserveWei } = {}) {
|
|
65
84
|
const need = toBig(reserveWei);
|
|
66
85
|
if (need === null || need <= 0n) return { measured: false, enough: null, show: false, balanceUnread: false };
|
|
@@ -69,16 +88,28 @@ export function gasReserveChoice({ nativeBalanceWei, reserveWei } = {}) {
|
|
|
69
88
|
return { measured: true, enough: have >= need, show: have < need, balanceUnread: false };
|
|
70
89
|
}
|
|
71
90
|
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
export function orderGasReservePlan({ gasPriceWei = null, nativeBalanceWei = null, nativeUsd = null, decimals = 18 } = {}) {
|
|
75
|
-
|
|
91
|
+
// THE WHOLE DECISION IN ONE OBJECT - exactly what is fixed in the form state before the quote. All numeric fields
|
|
92
|
+
// are strings or null: so the plan survives writing and reading, and BigInt does not become "[object BigInt]".
|
|
93
|
+
export function orderGasReservePlan({ gasPriceWei = null, nativeBalanceWei = null, nativeUsd = null, decimals = 18, depositGasLimit = 0n, extraFeeWei = 0n } = {}) {
|
|
94
|
+
// depositGasLimit is carried INTO the reserve (see orderGasReserveWei): on the no-own-native path the plan must
|
|
95
|
+
// be honest about the deposit the wallet will pay after the swap, so the reserve it decides on is larger. On a
|
|
96
|
+
// COMPOSED route extraFeeWei additionally carries the second leg's own fee, which is deducted from the swap
|
|
97
|
+
// proceeds - so the reserve must cover it too.
|
|
98
|
+
const reserveWei = orderGasReserveWei({ gasPriceWei, depositGasLimit, extraFeeWei });
|
|
99
|
+
const deposit = toBig(depositGasLimit);
|
|
100
|
+
const extra = toBig(extraFeeWei);
|
|
76
101
|
const display = reserveWei === null ? null : gasReserveDisplay({ reserveWei, nativeUsd, decimals });
|
|
77
102
|
const choice = gasReserveChoice({ nativeBalanceWei, reserveWei });
|
|
78
103
|
return {
|
|
79
104
|
measured: reserveWei !== null,
|
|
80
105
|
gasPriceWei: gasPriceWei === null || gasPriceWei === undefined ? null : String(gasPriceWei),
|
|
81
106
|
reserveWei: reserveWei === null ? null : reserveWei.toString(),
|
|
107
|
+
// THE DEPOSIT IS REPORTED SEPARATELY as well: a reader must be able to see how much of the reserve is the
|
|
108
|
+
// escrow deposit rather than the mark/refund, and a drift between this field and the constant reddens a check.
|
|
109
|
+
depositGasLimit: deposit === null ? null : deposit.toString(),
|
|
110
|
+
// THE SECOND LEG'S FEE IS REPORTED SEPARATELY as well, so a reader sees how much of the reserve is the
|
|
111
|
+
// conversion fee rather than gas or the deposit, and a drift between this field and the number reddens a check.
|
|
112
|
+
extraFeeWei: extra === null ? null : extra.toString(),
|
|
82
113
|
native: display ? display.native : null,
|
|
83
114
|
usd: display ? display.usd : null,
|
|
84
115
|
enough: choice.enough,
|
package/engine/evm/index.js
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
// GENERATED FILE - a byte-for-byte copy of the engine module www/js/evm/index.js for the SDK package.
|
|
2
|
-
// Edit the source under www/js
|
|
3
|
-
// tools/check-sdk-engine.mjs reddens on any drift, so a stale copy cannot ship silently.
|
|
2
|
+
// Edit the source under www/js and regenerate the mirror; a drift guard reddens on any difference.
|
|
4
3
|
// Everything below this header is identical to the source.
|
|
5
4
|
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// потому что мы движемся к настоящему продукту, а не к макету.
|
|
12
|
-
//
|
|
13
|
-
// Чего в демке по-прежнему НЕТ: переводов. Контракта escrow ещё не существует, адрес escrow
|
|
14
|
-
// генерируется моком (www/js/mock/chain.js), поэтому шаг фондирования остаётся имитацией -
|
|
15
|
-
// simulateEscrowFunding() ниже. Когда контракт появится, на его месте будет
|
|
16
|
-
// provider.sendTransaction/eth_sendTransaction, а имитация исчезнет вместе с моком цепочки.
|
|
5
|
+
// The wallet used by the demo interface.
|
|
6
|
+
// One implementation: WalletConnect (www/js/evm/walletconnect.js) - the user's real wallet, real balances.
|
|
7
|
+
// The built-in demo wallet and its mode switch were removed: we are heading to a real product, not a mockup.
|
|
8
|
+
// Still NO transfers: there is no escrow contract yet and the address is mocked (mock/chain.js), so funding
|
|
9
|
+
// is a simulation (simulateEscrowFunding below); provider.sendTransaction will replace it.
|
|
17
10
|
|
|
18
11
|
import {
|
|
19
12
|
address,
|
|
@@ -33,40 +26,43 @@ import {
|
|
|
33
26
|
restoreInjected,
|
|
34
27
|
} from "./session.js";
|
|
35
28
|
import { discoverWallets } from "./injected.js";
|
|
36
|
-
// fundOrder
|
|
37
|
-
//
|
|
29
|
+
// fundOrder needs a LOCAL name: `export * from ./funding.js` only re-exports and does not create a local
|
|
30
|
+
// variable, so fundOrderLive called a missing name and crashed.
|
|
38
31
|
import { fundOrder } from "./funding.js";
|
|
39
32
|
export * from "./factory.js";
|
|
40
33
|
export * from "./escrow.js";
|
|
41
34
|
export * from "./funding.js";
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
// кодом протокола, а не двумя похожими.
|
|
35
|
+
// The depositor signature form (evm/depositor.js) and the permit verdict (evm/permit.js) go through the SAME
|
|
36
|
+
// engine seam: the page and the SDK share one protocol code, not two lookalikes.
|
|
45
37
|
export * from "./depositor.js";
|
|
46
38
|
export * from "./permit.js";
|
|
39
|
+
// THE ASYNCHRONOUS ROUTE, EXECUTED - through the same engine seam as the decision that chooses it. The page reaches
|
|
40
|
+
// it through the bridge; the SDK carries the same module in its engine mirror (tools/build-sdk-engine.mjs).
|
|
41
|
+
export * from "./asyncRoute.js";
|
|
42
|
+
export * from "./asyncExec.js";
|
|
43
|
+
// THE LIQUIDITY LEG OF A COMPOSED ROUTE (KyberSwap Limit Order) - through the same engine seam as the CoW leg,
|
|
44
|
+
// so the page and the SDK carry one implementation each.
|
|
45
|
+
export * from "./asyncLegs.js";
|
|
47
46
|
|
|
48
|
-
// currentProvider -
|
|
49
|
-
//
|
|
47
|
+
// currentProvider - the wallet provider goes OUT to the SDK core (evm-wallet.mjs) so signing uses the same
|
|
48
|
+
// key as the page. Screens do not need it; they read status()/isConnected().
|
|
50
49
|
export { address, balanceOf, chainIdOf, connect, disconnect, isConnected, refreshBalances, restore, status, subscribe, switchChain, currentProvider };
|
|
51
50
|
export { connectInjected, restoreInjected };
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
// Ровно на этом уже падало дважды: сначала fundOrder, затем readContract - оба имени были доступны
|
|
55
|
-
// снаружи, но не внутри файла.
|
|
51
|
+
// IMPORTANT: this is an import, not a re-export. `export { X } from ...` only re-exports and does NOT create
|
|
52
|
+
// a local name, while fundOrderLive uses sendTransaction/readContract directly - this already broke twice.
|
|
56
53
|
import { sendTransaction, readContract, readReceipt, readCode } from "./session.js";
|
|
57
54
|
export { sendTransaction, readContract, readReceipt, readCode };
|
|
58
55
|
|
|
59
|
-
//
|
|
60
|
-
//
|
|
56
|
+
// The browser wallets available here (EIP-6963, falling back to window.ethereum). An empty list is normal:
|
|
57
|
+
// no extension, so WalletConnect remains.
|
|
61
58
|
export function wallets() {
|
|
62
59
|
return discoverWallets();
|
|
63
60
|
}
|
|
64
61
|
|
|
65
|
-
//
|
|
62
|
+
// Balances of all accepted tokens of the network (native first), for screens that need the list.
|
|
66
63
|
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
// В UI это сказано прямо: демка не двигает реальные деньги.
|
|
64
|
+
// SIMULATION: no real transaction is sent (there is no escrow contract). A fake hash is returned so the
|
|
65
|
+
// swap state stays derivable; the UI says plainly the demo moves no real money.
|
|
70
66
|
export async function simulateEscrowFunding(tx) {
|
|
71
67
|
await new Promise((r) => setTimeout(r, 900));
|
|
72
68
|
const bytes = new Uint8Array(32);
|
|
@@ -75,31 +71,28 @@ export async function simulateEscrowFunding(tx) {
|
|
|
75
71
|
return { hash, ...tx, simulated: true };
|
|
76
72
|
}
|
|
77
73
|
|
|
78
|
-
//
|
|
74
|
+
// THE LIVE FUNDING PATH: real transactions in the user's wallet.
|
|
79
75
|
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
76
|
+
// Replaces simulateEscrowFunding. The difference is fundamental: the simulation invented a hash, here two
|
|
77
|
+
// real transactions go out - createOrder to the factory and lock(sealedHalf) to the new escrow.
|
|
82
78
|
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
// (раздел 20.5), и только потом лочить.
|
|
79
|
+
// Separation is deliberate: cryptography (halves, DLEQ, envelope) lives in www/js/atomic/ and does NOT reach
|
|
80
|
+
// here. This function gets the ready sealedCommitment and sealedHalf - exactly what goes to the contract.
|
|
81
|
+
// The caller sets the order of steps: verify the counterparty first, then lock.
|
|
87
82
|
//
|
|
88
|
-
// factory
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
// ЧЕТЫРЕ ПОЛЯ И ДВА СРОКА ЯВНО. Сроки приходят готовыми (readyBy, t1), а не считаются здесь от текущего
|
|
96
|
-
// времени: они входят в контекст, к которому привязано доказательство, значит должны быть решены ДО него.
|
|
83
|
+
// factory is passed in (the caller takes it from the network config) so there is no second source of truth
|
|
84
|
+
// for addresses here.
|
|
85
|
+
// THE SIGNATURE WAS BROUGHT TO THE NEW SCHEME: the old hashlock/commitment/envelope fields remained, while
|
|
86
|
+
// the half commitments and ed25519 points that fundOrder REQUIRES were absent - so the live funding path
|
|
87
|
+
// could not pass even the first step. Neither syntax nor checks saw this, because the live path is never run.
|
|
88
|
+
// FOUR FIELDS AND TWO DEADLINES EXPLICITLY. The deadlines come ready (readyBy, t1), not computed from now:
|
|
89
|
+
// they go into the context the proof binds to, so they must be fixed before it.
|
|
97
90
|
export async function fundOrderLive({ factory, locker, claimer, commitHalfLocker, commitHalfClaimer, edPointLocker, edPointClaimer, edViewPointLocker, salt, amountWei, amountLabel, claimWindowSeconds = 3600, readyWindowSeconds = 14400, readyBy, t1, quote, depositorSignature, onStep }) {
|
|
98
91
|
return fundOrder({
|
|
99
92
|
factory,
|
|
100
|
-
quote, //
|
|
101
|
-
//
|
|
102
|
-
// createOrderAndFundByDepositor
|
|
93
|
+
quote, // signed quote: carries the fee, registry address and provider
|
|
94
|
+
// THE DEPOSITOR SIGNATURE OVER THE QUOTE DIGEST. Present: funding goes via
|
|
95
|
+
// createOrderAndFundByDepositor and anyone may send the transaction. Absent: the old path.
|
|
103
96
|
depositorSignature,
|
|
104
97
|
locker,
|
|
105
98
|
claimer,
|
|
@@ -108,16 +101,16 @@ export async function fundOrderLive({ factory, locker, claimer, commitHalfLocker
|
|
|
108
101
|
edPointLocker,
|
|
109
102
|
edPointClaimer,
|
|
110
103
|
edViewPointLocker,
|
|
111
|
-
salt, //
|
|
112
|
-
amountLabel, // "0.03 ETH"
|
|
104
|
+
salt, // retrying funding must land at the same escrow address
|
|
105
|
+
amountLabel, // "0.03 ETH" instead of the wei number on the button
|
|
113
106
|
amountWei,
|
|
114
107
|
claimWindowSeconds,
|
|
115
108
|
readyWindowSeconds,
|
|
116
|
-
readyBy, //
|
|
109
|
+
readyBy, // deadlines the proof is already bound to
|
|
117
110
|
t1,
|
|
118
111
|
call: readContract,
|
|
119
112
|
send: sendTransaction,
|
|
120
|
-
receipt: readReceipt, //
|
|
113
|
+
receipt: readReceipt, // the escrow address comes from the receipt, not from a prediction
|
|
121
114
|
onStep,
|
|
122
115
|
});
|
|
123
116
|
}
|
package/engine/evm/injected.js
CHANGED
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
// GENERATED FILE - a byte-for-byte copy of the engine module www/js/evm/injected.js for the SDK package.
|
|
2
|
-
// Edit the source under www/js
|
|
3
|
-
// tools/check-sdk-engine.mjs reddens on any drift, so a stale copy cannot ship silently.
|
|
2
|
+
// Edit the source under www/js and regenerate the mirror; a drift guard reddens on any difference.
|
|
4
3
|
// Everything below this header is identical to the source.
|
|
5
4
|
|
|
6
|
-
//
|
|
5
|
+
// BROWSER WALLETS: detection by EIP-6963 and connection by EIP-1193.
|
|
6
|
+
// WHY EIP-6963, NOT window.ethereum.isMetaMask. With two extensions installed, window.ethereum is "whoever was
|
|
7
|
+
// last", and guessing by flags gives wrong names and icons. EIP-6963 solves this: a wallet announces itself with
|
|
8
|
+
// an `eip6963:announceProvider` event (name, icon, provider), and the page requests it with `eip6963:requestProvider`.
|
|
9
|
+
// So the wallet list is real and updates if the user installs an extension with the tab open.
|
|
10
|
+
// window.ethereum stays as a fallback for old wallets; there the honest name is "Browser wallet".
|
|
11
|
+
// NO STATE HERE: this module only finds providers and does the handshake. State and balances live in evm/session.js.
|
|
7
12
|
//
|
|
8
|
-
// ПОЧЕМУ EIP-6963, А НЕ window.ethereum.isMetaMask. При двух установленных расширениях
|
|
9
|
-
// window.ethereum - это «кто успел последним», и угадывание по флагам даёт чужие имена и иконки:
|
|
10
|
-
// пользователь видит «MetaMask», а подключается Rabby. EIP-6963 решает это стандартно: кошелёк
|
|
11
|
-
// объявляет себя событием `eip6963:announceProvider` с именем, иконкой и своим провайдером, а
|
|
12
|
-
// страница просит объявиться событием `eip6963:requestProvider`. Так список кошельков настоящий,
|
|
13
|
-
// и он же обновляется, если пользователь поставил расширение при открытой вкладке.
|
|
14
13
|
//
|
|
15
|
-
// window.ethereum остаётся фолбэком для старых кошельков, которые 6963 ещё не умеют. В этом
|
|
16
|
-
// случае честное имя - «Browser wallet»: назвать его MetaMask мы не имеем права, не проверив.
|
|
17
14
|
//
|
|
18
|
-
// Здесь НЕТ состояния: этот модуль только находит провайдеров и делает рукопожатие. Состояние,
|
|
19
|
-
// балансы и смена сети живут в evm/session.js - общие для обоих коннекторов.
|
|
20
15
|
|
|
21
16
|
const ANNOUNCE = "eip6963:announceProvider";
|
|
22
17
|
const REQUEST = "eip6963:requestProvider";
|
|
23
18
|
|
|
24
|
-
//
|
|
19
|
+
// EIP-1193 codes that matter on screen: a user refusal is not an application error.
|
|
25
20
|
export const USER_REJECTED = 4001;
|
|
26
21
|
|
|
27
22
|
export function isUserRejection(error) {
|
|
@@ -30,7 +25,7 @@ export function isUserRejection(error) {
|
|
|
30
25
|
return /rejected|denied|cancell?ed|closed by user/i.test(String((error && error.message) || error || ""));
|
|
31
26
|
}
|
|
32
27
|
|
|
33
|
-
//
|
|
28
|
+
// A human name for the fallback: flags are all the old wallets have.
|
|
34
29
|
function fallbackName(eth) {
|
|
35
30
|
if (!eth) return null;
|
|
36
31
|
if (eth.isMetaMask) return "MetaMask";
|
|
@@ -41,9 +36,8 @@ function fallbackName(eth) {
|
|
|
41
36
|
return "Browser wallet";
|
|
42
37
|
}
|
|
43
38
|
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
// установленном кошельке (у расширения свой темп инициализации).
|
|
39
|
+
// Build the wallet list: first those announced by EIP-6963, then the window.ethereum fallback. timeoutMs is
|
|
40
|
+
// needed because announceProvider is an event: without a pause the list would be empty even with a wallet installed.
|
|
47
41
|
export function discoverWallets({ win = globalThis, timeoutMs = 250 } = {}) {
|
|
48
42
|
const found = [];
|
|
49
43
|
const seen = new Set();
|
|
@@ -70,7 +64,7 @@ export function discoverWallets({ win = globalThis, timeoutMs = 250 } = {}) {
|
|
|
70
64
|
if (win && typeof win.addEventListener === "function") {
|
|
71
65
|
win.addEventListener(ANNOUNCE, onAnnounce);
|
|
72
66
|
if (typeof win.dispatchEvent === "function") {
|
|
73
|
-
//
|
|
67
|
+
// We ask them to announce; answers arrive asynchronously, so we wait a short pause.
|
|
74
68
|
win.dispatchEvent(new Event(REQUEST));
|
|
75
69
|
}
|
|
76
70
|
}
|
|
@@ -78,8 +72,8 @@ export function discoverWallets({ win = globalThis, timeoutMs = 250 } = {}) {
|
|
|
78
72
|
return new Promise((resolve) => {
|
|
79
73
|
const finish = () => {
|
|
80
74
|
if (win && typeof win.removeEventListener === "function") win.removeEventListener(ANNOUNCE, onAnnounce);
|
|
81
|
-
//
|
|
82
|
-
//
|
|
75
|
+
// Fallback: an old wallet that does not know 6963 but sets window.ethereum. providers (array) appears with
|
|
76
|
+
// several wallets without 6963 support.
|
|
83
77
|
const legacy = win && win.ethereum;
|
|
84
78
|
if (!found.length && legacy) {
|
|
85
79
|
const list = Array.isArray(legacy.providers) && legacy.providers.length ? legacy.providers : [legacy];
|
|
@@ -94,12 +88,11 @@ export function discoverWallets({ win = globalThis, timeoutMs = 250 } = {}) {
|
|
|
94
88
|
});
|
|
95
89
|
}
|
|
96
90
|
|
|
97
|
-
//
|
|
98
|
-
//
|
|
91
|
+
// Subscribe to "a wallet appeared". Needed so the modal list is not a snapshot at open time: the user may install
|
|
92
|
+
// an extension without reloading.
|
|
99
93
|
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
// повторном запросе ответит снова, но снимок всё равно был бы потерян. Так список только дополняется.
|
|
94
|
+
// We work with the announcement itself, not a re-detection: the EIP-6963 event carries the name and provider, and
|
|
95
|
+
// events are not replayed, so a wallet that announced before our subscription would be lost on a re-request. The list only grows.
|
|
103
96
|
export function watchWallets(fn, { win = globalThis } = {}) {
|
|
104
97
|
if (!win || typeof win.addEventListener !== "function") return () => {};
|
|
105
98
|
const known = new Map();
|
|
@@ -120,16 +113,16 @@ export function watchWallets(fn, { win = globalThis } = {}) {
|
|
|
120
113
|
publish();
|
|
121
114
|
};
|
|
122
115
|
win.addEventListener(ANNOUNCE, onAnnounce);
|
|
123
|
-
//
|
|
124
|
-
//
|
|
116
|
+
// We ask them to announce: installed wallets answer right now and enter the list. An empty list is not handed
|
|
117
|
+
// out, else the UI would be cleared just because there are no wallets.
|
|
125
118
|
if (typeof win.dispatchEvent === "function") win.dispatchEvent(new Event(REQUEST));
|
|
126
119
|
return () => win.removeEventListener(ANNOUNCE, onAnnounce);
|
|
127
120
|
}
|
|
128
121
|
|
|
129
|
-
//
|
|
122
|
+
// EIP-1193 handshake: ask for accounts (here the wallet asks permission) and learn the network.
|
|
130
123
|
export async function handshake(provider) {
|
|
131
124
|
if (!provider || typeof provider.request !== "function") {
|
|
132
|
-
throw new Error("
|
|
125
|
+
throw new Error("This wallet does not support EIP-1193 (no request)");
|
|
133
126
|
}
|
|
134
127
|
const accounts = await provider.request({ method: "eth_requestAccounts" });
|
|
135
128
|
const address = Array.isArray(accounts) ? accounts[0] : null;
|
|
@@ -137,10 +130,9 @@ export async function handshake(provider) {
|
|
|
137
130
|
return { address: address || null, chainId: Number(chainIdHex) || null };
|
|
138
131
|
}
|
|
139
132
|
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
// загрузке не должна выкидывать окно подключения.
|
|
133
|
+
// A silent check "the site is already allowed for this wallet" - for restoring after a reload. eth_accounts does
|
|
134
|
+
// NOT show the wallet window: an empty answer means "no permission", a normal state, not an error. That is why
|
|
135
|
+
// eth_requestAccounts must not be called here: the page must not pop a connect window on load.
|
|
144
136
|
export async function silentAccounts(provider) {
|
|
145
137
|
if (!provider || typeof provider.request !== "function") return [];
|
|
146
138
|
try {
|
|
@@ -151,25 +143,25 @@ export async function silentAccounts(provider) {
|
|
|
151
143
|
}
|
|
152
144
|
}
|
|
153
145
|
|
|
154
|
-
//
|
|
146
|
+
// Why the wallet may not have opened - translate the error code into a plain reason.
|
|
155
147
|
//
|
|
156
|
-
// -32002
|
|
157
|
-
//
|
|
158
|
-
export function explainInjectedError(e, label = "
|
|
148
|
+
// -32002 is the most common cause of "pressed but no window": the wallet already has an open request (the window
|
|
149
|
+
// hangs on another screen/tab, or the previous attempt did not finish).
|
|
150
|
+
export function explainInjectedError(e, label = "Wallet") {
|
|
159
151
|
const code = e && (e.code || (e.data && e.data.originalError && e.data.originalError.code));
|
|
160
152
|
const message = String((e && e.message) || e);
|
|
161
153
|
if (code === -32002 || /already pending|already processing/i.test(message)) {
|
|
162
154
|
return (
|
|
163
155
|
label +
|
|
164
|
-
":
|
|
165
|
-
"
|
|
156
|
+
": the wallet already has a pending request, so a new window did not open. " +
|
|
157
|
+
"Open the extension, finish or cancel that request, then try again."
|
|
166
158
|
);
|
|
167
159
|
}
|
|
168
160
|
if (/no provider|not connected|provider is disconnected|undefined is not a function/i.test(message)) {
|
|
169
|
-
return label + ":
|
|
161
|
+
return label + ": the extension is not responding (the browser may have unloaded it, or the page is not where it works).";
|
|
170
162
|
}
|
|
171
163
|
if (/user rejected|user denied|rejected by user/i.test(message) || code === 4001) {
|
|
172
|
-
return label + ":
|
|
164
|
+
return label + ": the request was rejected in the wallet.";
|
|
173
165
|
}
|
|
174
166
|
return label + ": " + message;
|
|
175
167
|
}
|