@ninsei-labs/sdk 0.39.2 → 0.40.0-develop.1
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 +63 -0
- package/README.md +4 -1
- 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 +554 -449
- 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 +26 -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 +5 -5
- package/src/codes.mjs +5 -0
- package/src/config.mjs +1 -1
- package/src/engine.mjs +4 -0
- package/src/index.mjs +16 -2
- 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 +23 -5
- package/src/swaps.mjs +18 -1
package/engine/sdk/bridge.js
CHANGED
|
@@ -1,85 +1,92 @@
|
|
|
1
1
|
// GENERATED FILE - a byte-for-byte copy of the engine module www/js/sdk/bridge.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 PAGE-TO-CORE SHIM: THE ONE PLACE WHERE SCREENS KNOW ABOUT THE SDK (sdk/).
|
|
7
6
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// только он.
|
|
7
|
+
// WHY IT EXISTS. The swap logic lives in the core (sdk/, the @ninsei-labs/sdk package) while the page should do
|
|
8
|
+
// only markup, screen state and texts. Before this shim every screen called the engine itself and the logic
|
|
9
|
+
// spread across two places. Now a screen calls the SHIM, and only it knows about the core.
|
|
12
10
|
//
|
|
13
|
-
// ЧТО СКЛЕЙНИК ПОДСОВЫВАЕТ ЯДРУ - ровно те швы, которые ядро просит снаружи и само достать не может:
|
|
14
|
-
// storage - хранилище страницы: сделки и сессия читаются оттуда же, где их кладёт страница (core/store.js);
|
|
15
|
-
// serverAuth - пропуск на наш сервис: подпись сообщения о входе умеет только кошелёк (evm/auth.js signIn),
|
|
16
|
-
// ядро получает уже ГОТОВЫЙ пропуск;
|
|
17
|
-
// evmCall - чтение цепи КОШЕЛЬКОМ СТРАНИЦЫ: своего провайдера у ядра нет и быть не должно;
|
|
18
|
-
// wallet - адаптер кошелька страницы (sdk/src/adapters/evm-wallet.mjs): подпись возможна только в нём.
|
|
19
11
|
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
12
|
+
// WHAT THE SHIM PASSES TO THE CORE - exactly the seams the core asks for from outside and cannot get itself:
|
|
13
|
+
// storage - the page's storage: deals and session are read from where the page puts them (core/store.js);
|
|
14
|
+
// serverAuth - a pass to our service: only the wallet can sign the sign-in message (evm/auth.js signIn),
|
|
15
|
+
// so the core gets the pass READY-MADE;
|
|
16
|
+
// evmCall - chain reads WITH THE PAGE'S WALLET: the core has no provider of its own and must not;
|
|
17
|
+
// wallet - the page wallet adapter (sdk/src/adapters/evm-wallet.mjs): signing happens only in it.
|
|
22
18
|
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
19
|
+
// WHAT THE SHIM DOES NOT DO. It computes neither thresholds nor step order nor the escrow address: method names
|
|
20
|
+
// and paths are only those that EXIST in the core, and the decisions stay in the core.
|
|
21
|
+
//
|
|
22
|
+
// ABOUT THE CORE BEING AVAILABLE TO THE PAGE - IT IS NOW BUILT, NOT WAITING FOR A BUILD.
|
|
23
|
+
// * sdk/src/primitives.mjs imports @noble/curves and @noble/hashes by BARE package names, so the page is
|
|
24
|
+
// served not the sdk/ source but a BUILT BUNDLE (www/assets/vendors/sdk/sdk-browser.js, the same path as the
|
|
25
|
+
// atomic-swap crypto bundle). The bundle exposes the WHOLE FACADE:
|
|
26
|
+
// createNinsei (config/wallet/quotes/preflight/swaps/actions/order/sweep/recovery/sim) plus the browser
|
|
27
|
+
// adapters (evmWallet, localStorageAdapter/memoryAdapter). So starting a swap (swaps.start) and facade
|
|
28
|
+
// quotes ARE available to the page - a "facade not served to the page" refusal is no longer expected.
|
|
29
|
+
// * The bundle link carries ?v=<hash>, so the edge cache resets itself after a rebuild.
|
|
30
|
+
//
|
|
31
|
+
//
|
|
32
|
+
// THE ORDER ACTIONS HAVE NO FALLBACK PATH ANY MORE, AND THAT IS A CONSEQUENCE OF THE MOVE. The deal engine used
|
|
33
|
+
// to sit on the page and, with the bundle unavailable, the order actions ran on it - "the same functions", as it
|
|
34
|
+
// was written here. Now the deal engine is a module OF THE PACKAGE (sdk/src/swap-flow.mjs): there is no second
|
|
35
|
+
// copy on the page, so no fallback can exist. The bundle did not load (missing file, old cache, network) - that
|
|
36
|
+
// is a NAMED refusal with the cause in the console (sdkBundle below), not silence and not a substitution.
|
|
32
37
|
//
|
|
33
|
-
// ЗАПАСНОГО ПУТИ У ДЕЙСТВИЙ ОРДЕРА БОЛЬШЕ НЕТ, И ЭТО НЕ ПОТЕРЯ, А СЛЕДСТВИЕ ПЕРЕЕЗДА (#32, волна 3). Раньше
|
|
34
|
-
// www/js/core/swap-flow.js лежал на странице, и при недоступном бандле действия ордера шли им же - «одни и те
|
|
35
|
-
// же функции», как здесь и было написано. Теперь движок сделки - СОБСТВЕННЫЙ модуль пакета
|
|
36
|
-
// (sdk/src/swap-flow.mjs): второй копии на странице нет, значит и запасного пути быть не может. Бандл не
|
|
37
|
-
// загрузился (нет файла, старый кеш, сеть) - это НАЗВАННЫЙ отказ с причиной в консоли (sdkBundle ниже), а не
|
|
38
|
-
// молчание и не подмена.
|
|
39
38
|
|
|
40
39
|
import { chainById, DEFAULT_CHAIN, MONERO, allowedProvidersFor, knownFactoryCodesFor, knownImplementationCodesFor } from "../core/config.js";
|
|
41
40
|
import { storage as pageStorage } from "../core/store.js";
|
|
42
41
|
import { token as authToken, signIn } from "../evm/auth.js";
|
|
43
42
|
import * as evm from "../evm/index.js";
|
|
44
|
-
//
|
|
45
|
-
// (core/finality.js),
|
|
43
|
+
// ORDER TERMS FOR THE CORE ARE ASSEMBLED FROM DATA, NOT FROM RULES: the windows come from the finality policy
|
|
44
|
+
// (core/finality.js), the salt from the engine's generator (evm/funding.js). No deadlines or numbers of its own here.
|
|
46
45
|
import { orderWindows } from "../core/finality.js";
|
|
47
46
|
import { newSecret } from "../evm/funding.js";
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
// (tools/check-signing-guards.mjs, tools/check-arrival-depositor.mjs), видит прежний вызов.
|
|
52
|
-
// СПИСОК СДЕЛОК И ЕГО ОБСЛУЖИВАНИЕ (экран #/swaps). Состояния отдаёт ЯДРО: swaps.list - показ, swaps.sync -
|
|
53
|
-
// слияние с серверным списком, swaps.forget - уборка записи. Ядру для этого нужны только швы страницы
|
|
54
|
-
// (пропуск и хранилище), и оба уже подсунуты выше - своих правил слияния склейник не заводит.
|
|
47
|
+
// THE ORDER CALLS - ACTION AND READ - COME FROM THE CORE. The deal engine moved into the package, and the shim
|
|
48
|
+
// exposes EXACTLY the same names (markReadyOrder/claimOrder/refundOrder/orderStatus/orderDeadlines), so a screen
|
|
49
|
+
// changes only the import source, not the call expression - and the guard that fixes the call site sees the old call.
|
|
55
50
|
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
51
|
+
// THE DEAL LIST AND ITS UPKEEP (the #/swaps screen). States come from the CORE: swaps.list - display, swaps.sync -
|
|
52
|
+
// merging with the server list, swaps.forget - dropping a record. The core needs only the page's seams for this
|
|
53
|
+
// (the pass and the storage), and both are already passed above - the shim adds no rules of its own.
|
|
54
|
+
//
|
|
55
|
+
// WATCHING IS A PAGE MECHANISM, NOT THE CORE'S: the poll tick lives in app.js, so the focus stays in
|
|
56
|
+
// core/swap.js and the screen only declares it to the shim.
|
|
58
57
|
import { setLiveFocus, dealSwapIds, serverRestoreHeightFor, STEP_LABELS,
|
|
59
58
|
confirmReady as engineConfirmReady, refundEth as engineRefundEth, sweepNow as engineSweepNow,
|
|
60
59
|
getSwap as engineGetSwap, saveSwap as engineSaveSwap } from "../core/swap.js";
|
|
61
|
-
//
|
|
62
|
-
//
|
|
60
|
+
// THE FEE RATE AND THE ORDER STATE - CHAIN READS WITH THE PAGE'S WALLET: the reference panel ("how it works")
|
|
61
|
+
// and recovery-file parsing take them. The page gets them FROM HERE, not directly from evm/*.
|
|
63
62
|
import { cachedFeeRate } from "../evm/fees.js";
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
63
|
+
// MONERO ADDRESS AND HEIGHT - DELIBERATE PAGE READS (the progress screen): checking the recipient address
|
|
64
|
+
// format and the node height for the scan height in the recovery file. The address logic lives in the core
|
|
65
|
+
// (swaps.addressNetwork), here a fallback by the same module; the node height is the page node's read.
|
|
67
66
|
import { networkFromShape } from "../monero/address.js";
|
|
68
67
|
import { height as nodeHeightValue } from "../monero/node.js";
|
|
69
68
|
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
const SDK_BUNDLE = "/assets/vendors/sdk/sdk-browser.js?v=
|
|
69
|
+
// THE CORE ADDRESS AS A STRING - THE BUILT BUNDLE UNDER www/: the page gets the core as ONE module, not a pile
|
|
70
|
+
// of sdk/ sources; ?v=<hash> keeps the cache fresh.
|
|
71
|
+
const SDK_BUNDLE = "/assets/vendors/sdk/sdk-browser.js?v=3ce64c53";
|
|
72
|
+
|
|
73
|
+
// A NAMED SEAM FOR CHECKS - THE SAME TECHNIQUE AS sdkBookUse BELOW. The asynchronous path is driven against a
|
|
74
|
+
// stand-in order book (the demo network has no provider), and the ordinary escrow funding that follows a settled
|
|
75
|
+
// swap can be replaced while that runs, because deploying an escrow factory on a throwaway chain is the stand's
|
|
76
|
+
// job, not a check's. The replacement is named, set only by a check, and unset by the same function; production
|
|
77
|
+
// never calls it, so the real funding path is what ships.
|
|
78
|
+
let startSwapOverride = null;
|
|
79
|
+
export function useStartSwap(fn = null) { startSwapOverride = typeof fn === "function" ? fn : null; return Boolean(startSwapOverride); }
|
|
73
80
|
|
|
74
|
-
//
|
|
81
|
+
// ONE LOAD PER PAGE. A refusal is a state, not a breakdown: it is named in the console and the caller decides.
|
|
75
82
|
let loading = null;
|
|
76
83
|
export async function sdkBundle() {
|
|
77
84
|
if (!loading) {
|
|
78
85
|
loading = (async () => {
|
|
79
86
|
try { return await import(SDK_BUNDLE); }
|
|
80
87
|
catch (error) {
|
|
81
|
-
console.warn("[bridge]
|
|
82
|
-
"):
|
|
88
|
+
console.warn("[bridge] the built SDK core was not served to the page (" + ((error && error.message) || error) +
|
|
89
|
+
"): actions go by the previous engine call; see www/js/sdk/bridge.js");
|
|
83
90
|
return null;
|
|
84
91
|
}
|
|
85
92
|
})();
|
|
@@ -87,8 +94,8 @@ export async function sdkBundle() {
|
|
|
87
94
|
return loading;
|
|
88
95
|
}
|
|
89
96
|
|
|
90
|
-
//
|
|
91
|
-
//
|
|
97
|
+
// THE SURFACES FROM THE BUNDLE - EXACTLY THE NAMES USED BELOW. So a screen need not know the core came as one
|
|
98
|
+
// file rather than three: the call form does not change.
|
|
92
99
|
export async function sdkCoreModules() {
|
|
93
100
|
const mod = await sdkBundle();
|
|
94
101
|
if (!mod) return null;
|
|
@@ -99,7 +106,7 @@ export async function sdkCoreModules() {
|
|
|
99
106
|
};
|
|
100
107
|
}
|
|
101
108
|
|
|
102
|
-
//
|
|
109
|
+
// THE CORE FACADE (config/quotes/swaps/actions/recovery whole) - THE SAME bundle, only its createNinsei is needed.
|
|
103
110
|
async function coreFacade() {
|
|
104
111
|
const mod = await sdkBundle();
|
|
105
112
|
return mod ? { factory: mod.createNinsei } : null;
|
|
@@ -109,8 +116,8 @@ function modeOf(chain) {
|
|
|
109
116
|
return chain && chain.escrow && chain.escrow.mode === "live" ? "live" : "sim";
|
|
110
117
|
}
|
|
111
118
|
|
|
112
|
-
//
|
|
113
|
-
//
|
|
119
|
+
// CORE SETTINGS FROM THE PAGE. No value here decides anything FOR the core: it is the service address, the
|
|
120
|
+
// network, the storage and the seams the core asks for from outside.
|
|
114
121
|
function optionsFor(chain) {
|
|
115
122
|
return {
|
|
116
123
|
settlement: { chain: chain.id },
|
|
@@ -118,38 +125,38 @@ function optionsFor(chain) {
|
|
|
118
125
|
apiBase: "/api",
|
|
119
126
|
assetsBase: "/",
|
|
120
127
|
mode: modeOf(chain),
|
|
121
|
-
//
|
|
128
|
+
// THE PAGE STORAGE BECOMES THE CORE STORAGE: deal records and the session live in one place.
|
|
122
129
|
storage: pageStorage(),
|
|
123
|
-
//
|
|
130
|
+
// A PASS TO OUR SERVICE: the core only presents it; the page wallet obtains it.
|
|
124
131
|
serverAuth: async () => {
|
|
125
132
|
if (authToken()) return authToken();
|
|
126
133
|
try { await signIn(); } catch { return null; }
|
|
127
134
|
return authToken();
|
|
128
135
|
},
|
|
129
|
-
//
|
|
136
|
+
// CHAIN READS - WITH THE PAGE'S WALLET (the core needs this seam: it has no provider of its own).
|
|
130
137
|
evmCall: (request) => evm.readContract(request),
|
|
131
|
-
//
|
|
138
|
+
// CONTRACT CODE - WITH THE PAGE'S WALLET: needed by the factory-code check, extcodehash is computed from it.
|
|
132
139
|
evmCode: (address) => evm.readCode({ address }),
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
140
|
+
// OUR ALLOW-LIST - INTERFACE POLICY. The core confirms with the CHAIN whose key signed the quote (the maker
|
|
141
|
+
// registry); this list decides whom the PAGE trades with. A provider outside the list fails with the code
|
|
142
|
+
// `quote-provider-not-allowed` - and the refusal is visible BEFORE signing, because without a firm quote
|
|
143
|
+
// there is neither a fee rate nor a lock. The list comes from the network registry (core/config.js,
|
|
144
|
+
// allowedProvidersFor), not invented here; a network without a list = no policy.
|
|
138
145
|
allowedProviders: allowedProvidersFor(chain),
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
//
|
|
146
|
+
// THE LIST OF KNOWN FACTORY BUILDS - INTERFACE POLICY, next to allowedProviders. The core takes the factory
|
|
147
|
+
// from the provider registry record and compares its CODE against this list (extcodehash). Empty = no policy;
|
|
148
|
+
// then the factory must still match the signed quote.
|
|
142
149
|
knownFactoryCodes: knownFactoryCodesFor(chain),
|
|
143
|
-
//
|
|
144
|
-
// (implementation, implementationCodeHash)
|
|
145
|
-
//
|
|
146
|
-
//
|
|
150
|
+
// THE HASH OF A KNOWN ESCROW-IMPLEMENTATION BUILD - NEXT TO knownFactoryCodes. The factory compares the pair
|
|
151
|
+
// (implementation, implementationCodeHash) at order creation; the core compares THE SAME pair on chain, and
|
|
152
|
+
// this list is interface policy: which implementation builds it accepts. Empty = no policy (a network with an
|
|
153
|
+
// old factory), and then the pair is still read and the code at the implementation address must be non-empty.
|
|
147
154
|
knownImplementationCodes: knownImplementationCodesFor(chain),
|
|
148
155
|
};
|
|
149
156
|
}
|
|
150
157
|
|
|
151
|
-
//
|
|
152
|
-
//
|
|
158
|
+
// ONE CORE INSTANCE PER NETWORK: the facade holds storage and subscriptions, and a second instance for the same
|
|
159
|
+
// network would mean a second poll. Unavailable - null, and the caller names the refusal itself.
|
|
153
160
|
const instances = new Map();
|
|
154
161
|
async function instanceFor(chainSlug) {
|
|
155
162
|
const facade = await coreFacade();
|
|
@@ -159,24 +166,24 @@ async function instanceFor(chainSlug) {
|
|
|
159
166
|
return { chain, sdk: instances.get(chain.id) };
|
|
160
167
|
}
|
|
161
168
|
|
|
162
|
-
//
|
|
163
|
-
//
|
|
169
|
+
// THE PAGE WALLET FOR THE CORE: an adapter over ITS provider. Taken AT THE MOMENT of an action: the provider
|
|
170
|
+
// appears with the connection, not at page load.
|
|
164
171
|
function walletFor(mods) {
|
|
165
172
|
const provider = typeof evm.currentProvider === "function" ? evm.currentProvider() : null;
|
|
166
173
|
if (!provider) return null;
|
|
167
174
|
return mods.wallet.evmWallet(provider);
|
|
168
175
|
}
|
|
169
176
|
|
|
170
|
-
// ---
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
177
|
+
// --- ORDER ACTIONS -------------------------------------------------------------------------------
|
|
178
|
+
// THE NAMES AND THE REQUEST SHAPE ARE THE SAME AS THE SCREEN'S FORMER CALLS. The screen passes the order
|
|
179
|
+
// expectations (expect) and recomputes nothing: the core checks slots against the chain BEFORE signing and does
|
|
180
|
+
// not sign without expectations. The wallet is the one that signs the page; the core needs no network here
|
|
181
|
+
// (reading and sending go through the same provider as before).
|
|
175
182
|
export async function markReadyOrder({ escrow, expect } = {}) {
|
|
176
183
|
const mods = await sdkCoreModules();
|
|
177
184
|
const wallet = mods ? walletFor(mods) : null;
|
|
178
|
-
//
|
|
179
|
-
if (!mods || !wallet) throw new Error("[bridge]
|
|
185
|
+
// THE CORE AND THE WALLET ARE MANDATORY: there is no fallback path (an engine on the page) any more. The refusal is named, not silence.
|
|
186
|
+
if (!mods || !wallet) throw new Error("[bridge] nothing to sign the readiness mark with: " + (mods ? "wallet not connected" : "the SDK core was not served to the page"));
|
|
180
187
|
return await mods.actions.createActions({ call: (r) => evm.readContract(r) })
|
|
181
188
|
.markReady({ escrow, expect }, wallet);
|
|
182
189
|
}
|
|
@@ -184,7 +191,7 @@ export async function markReadyOrder({ escrow, expect } = {}) {
|
|
|
184
191
|
export async function claimOrder({ escrow, halfClaimer, expect } = {}) {
|
|
185
192
|
const mods = await sdkCoreModules();
|
|
186
193
|
const wallet = mods ? walletFor(mods) : null;
|
|
187
|
-
if (!mods || !wallet) throw new Error("[bridge]
|
|
194
|
+
if (!mods || !wallet) throw new Error("[bridge] nothing to sign the claim with: " + (mods ? "wallet not connected" : "the SDK core was not served to the page"));
|
|
188
195
|
return await mods.actions.createActions({ call: (r) => evm.readContract(r) })
|
|
189
196
|
.claim({ escrow, halfClaimer, expect }, wallet);
|
|
190
197
|
}
|
|
@@ -192,18 +199,18 @@ export async function claimOrder({ escrow, halfClaimer, expect } = {}) {
|
|
|
192
199
|
export async function refundOrder({ escrow, halfLocker } = {}) {
|
|
193
200
|
const mods = await sdkCoreModules();
|
|
194
201
|
const wallet = mods ? walletFor(mods) : null;
|
|
195
|
-
if (!mods || !wallet) throw new Error("[bridge]
|
|
196
|
-
//
|
|
197
|
-
//
|
|
202
|
+
if (!mods || !wallet) throw new Error("[bridge] nothing to sign the refund with: " + (mods ? "wallet not connected" : "the SDK core was not served to the page"));
|
|
203
|
+
// THERE ARE NO EXPECTATIONS HERE ON PURPOSE: the refund screen did not pass any, and adding them would enable
|
|
204
|
+
// slot comparison where it was not - i.e. change the refund behaviour.
|
|
198
205
|
return await mods.actions.createActions({ call: (r) => evm.readContract(r) })
|
|
199
206
|
.refund({ escrow, halfLocker }, wallet);
|
|
200
207
|
}
|
|
201
208
|
|
|
202
|
-
// ---
|
|
203
|
-
//
|
|
204
|
-
// (
|
|
205
|
-
//
|
|
206
|
-
//
|
|
209
|
+
// --- AUTOMATIC EARLY REFUND ---------------------------------------------------------------------
|
|
210
|
+
// THE DECISION STAYS IN THE CORE. The screen only passes the deal record, the order expectations and the network;
|
|
211
|
+
// the arrival check (two nodes of different operators on one block) and the "time to refund" decision are the
|
|
212
|
+
// core's (swaps.refundIfXmrMissing). The witness nodes come from the settings of THE SAME core (config.nodesFor),
|
|
213
|
+
// not invented here: the list lives as one truth per network. The wallet is the same page adapter that signs the other order actions.
|
|
207
214
|
export async function sdkAutoRefund(request) {
|
|
208
215
|
const ctx = await instanceFor(request && request.chain);
|
|
209
216
|
if (!ctx) return null;
|
|
@@ -219,17 +226,17 @@ export async function sdkAutoRefund(request) {
|
|
|
219
226
|
return ctx.sdk.swaps.refundIfXmrMissing(req);
|
|
220
227
|
}
|
|
221
228
|
|
|
222
|
-
// ---
|
|
223
|
-
//
|
|
229
|
+
// --- RECOVERY-FILE PARSING -----------------------------------------------------------------------
|
|
230
|
+
// The parsing module is served to the browser, so this is a real core path, not a fallback.
|
|
224
231
|
export async function sdkOpenRecovery(file, passphrase) {
|
|
225
232
|
const mods = await sdkCoreModules();
|
|
226
233
|
if (!mods) return null;
|
|
227
234
|
return await mods.recovery.createRecovery().open(file, passphrase);
|
|
228
235
|
}
|
|
229
236
|
|
|
230
|
-
// ---
|
|
231
|
-
//
|
|
232
|
-
//
|
|
237
|
+
// --- FACADE SURFACES (quotes, deal state, swap start) ---------------------------------------------
|
|
238
|
+
// The core is served to the page as a bundle, so these calls go through the REAL facade. They answer null only
|
|
239
|
+
// if the bundle itself did not load - and then the cause is named in the console, not hidden.
|
|
233
240
|
|
|
234
241
|
export async function sdkWatchQuotes(request, onSnapshot) {
|
|
235
242
|
const ctx = await instanceFor(request && request.chain);
|
|
@@ -242,37 +249,37 @@ export async function sdkQuotesSnapshot(chainSlug) {
|
|
|
242
249
|
return ctx ? ctx.sdk.quotes.snapshot() : null;
|
|
243
250
|
}
|
|
244
251
|
|
|
245
|
-
// ---
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
252
|
+
// --- THE INDICATIVE QUOTE BOOK ON THE CORE ---------------------------------------------------------
|
|
253
|
+
// THE BOOK (offers and refusals) COMES FROM THE CORE: quotes.watch subscribes to the core poll, quotes.snapshot
|
|
254
|
+
// returns the last snapshot without waiting. The shim does exactly ONE job here - TRANSLATION OF SHAPE: the core
|
|
255
|
+
// snapshot's field names are mapped to those the screen already draws. There is no selection or priority rule
|
|
256
|
+
// here: offer, refusal or best is decided by the core (sdk/src/quotes.mjs, readBook). The core is silent or
|
|
257
|
+
// refused - the book is empty, and the former (engine) book is not substituted: it no longer exists.
|
|
251
258
|
//
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
let bookStop = null; //
|
|
256
|
-
let bookKey = null; //
|
|
257
|
-
let bookCore = null; //
|
|
258
|
-
let bookResume = null; //
|
|
259
|
-
//
|
|
260
|
-
//
|
|
259
|
+
// SUBSCRIPTION IS ONE. The core polls for the duration of the subscription; a second listener would be a second
|
|
260
|
+
// poll, so the previous subscription is removed BEFORE the new one. The last snapshot survives re-subscription:
|
|
261
|
+
// the reader sees the previous book until a fresh one arrives - not emptiness on every tick.
|
|
262
|
+
let bookStop = null; // unsubscribe from the core's current subscription
|
|
263
|
+
let bookKey = null; // which request (network|side|token|size) this subscription is for
|
|
264
|
+
let bookCore = null; // the last CORE snapshot (not the translation): the translation is done on read
|
|
265
|
+
let bookResume = null; // waiting for the first tick after subscribing
|
|
266
|
+
// A SEAM HOOK (sdkBookUse): a core quote surface brought from outside. Needed by checks that run WITHOUT a
|
|
267
|
+
// browser: the core itself is not in the bundle there, and the book must be checked. Not set in production.
|
|
261
268
|
let bookQuotes = null;
|
|
262
269
|
|
|
263
|
-
//
|
|
270
|
+
// THE CORE FOR CHECKS WITHOUT A BROWSER: put in a quote surface (watch/snapshot) and work with it.
|
|
264
271
|
export function sdkBookUse(quotesApi) {
|
|
265
272
|
bookQuotes = quotesApi || null;
|
|
266
273
|
bookCore = null;
|
|
267
274
|
bookKey = null;
|
|
268
275
|
bookResume = null;
|
|
269
|
-
if (bookStop) { try { bookStop(); } catch { /*
|
|
276
|
+
if (bookStop) { try { bookStop(); } catch { /* already removed */ } }
|
|
270
277
|
bookStop = null;
|
|
271
278
|
}
|
|
272
279
|
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
//
|
|
280
|
+
// TRANSLATING A CORE ROW INTO A SCREEN ROW. Names only: values are carried as is. The age is computed
|
|
281
|
+
// HERE (from the quote's own timestamp): the core computed it on its own tick, while display asks for freshness
|
|
282
|
+
// now - otherwise the quote's lifetime would be rejuvenated by a poll tick.
|
|
276
283
|
function bookRow(o) {
|
|
277
284
|
const at = Number.isFinite(Number(o.at)) ? Number(o.at) : null;
|
|
278
285
|
return {
|
|
@@ -287,16 +294,16 @@ function bookRow(o) {
|
|
|
287
294
|
};
|
|
288
295
|
}
|
|
289
296
|
|
|
290
|
-
//
|
|
291
|
-
//
|
|
297
|
+
// THE REFUSAL KIND WITH WHICH THE SCREEN NAMES THE CAUSE. The core code `disabled` is called `off` by the
|
|
298
|
+
// screen; other code names match, and there is no reason to rename them.
|
|
292
299
|
const REFUSAL_KIND = { disabled: "off" };
|
|
293
300
|
function bookRefusal(r) {
|
|
294
301
|
return { ...bookRow(r), code: r.code, kind: REFUSAL_KIND[r.code] || r.code, why: r.why };
|
|
295
302
|
}
|
|
296
303
|
|
|
297
|
-
//
|
|
298
|
-
// (
|
|
299
|
-
//
|
|
304
|
+
// CORE SNAPSHOT -> SCREEN SNAPSHOT. The shape is the one the screen had: ok/error/data/at, and in data -
|
|
305
|
+
// references (the reference rate) and best. A connection failure does not turn into the former numbers: ok is
|
|
306
|
+
// dropped and the screen shows an honest state. Core silence (no snapshot) is also an empty book, not the former one.
|
|
300
307
|
function bookOf(core) {
|
|
301
308
|
if (!core) return { ok: false, error: null, data: null, at: 0, fetching: false };
|
|
302
309
|
const offers = (Array.isArray(core.offers) ? core.offers : []).map(bookRow);
|
|
@@ -309,7 +316,7 @@ function bookOf(core) {
|
|
|
309
316
|
fetching: false,
|
|
310
317
|
data: {
|
|
311
318
|
offers, refused, quotes: offers,
|
|
312
|
-
//
|
|
319
|
+
// THE BEST, AS THE SERVICE NAMED IT: by it the screen confirms its "best" mark by pair and provider.
|
|
313
320
|
best: core.best || null,
|
|
314
321
|
seq: core.seq === undefined ? null : core.seq,
|
|
315
322
|
references: Array.isArray(core.references) ? core.references : [],
|
|
@@ -318,31 +325,31 @@ function bookOf(core) {
|
|
|
318
325
|
};
|
|
319
326
|
}
|
|
320
327
|
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
//
|
|
328
|
+
// ASKING THE CORE FOR THE BOOK. The subscription is ONE and is replayed only when the REQUEST CHANGED: while
|
|
329
|
+
// size and side are the same, the core polls the book on its own tick and no second poll is created. When the
|
|
330
|
+
// request changed, the caller waits for the first tick and gets a FRESH snapshot, not a previous one. The core
|
|
331
|
+
// did not come up - empty (and the console names why).
|
|
325
332
|
export async function sdkBook({ chain, direction, token, size } = {}) {
|
|
326
333
|
let quotes = bookQuotes;
|
|
327
|
-
let instance = "injected"; //
|
|
334
|
+
let instance = "injected"; // the hook (seam) has no network: its instance is one
|
|
328
335
|
if (!quotes) {
|
|
329
336
|
const ctx = await instanceFor(chain);
|
|
330
337
|
if (!ctx) {
|
|
331
|
-
if (bookStop) { try { bookStop(); } catch { /*
|
|
338
|
+
if (bookStop) { try { bookStop(); } catch { /* already removed */ } bookStop = null; }
|
|
332
339
|
bookKey = null;
|
|
333
340
|
bookResume = null;
|
|
334
341
|
bookCore = null;
|
|
335
342
|
return null;
|
|
336
343
|
}
|
|
337
344
|
quotes = ctx.sdk.quotes;
|
|
338
|
-
instance = ctx.chain.id; //
|
|
345
|
+
instance = ctx.chain.id; // books of different networks must not be mixed: the network is part of the key
|
|
339
346
|
}
|
|
340
347
|
const dir = direction === "sell" ? "sell" : "buy";
|
|
341
348
|
const key = instance + "|" + dir + "|" + String(token || "") + "|" + String(size === undefined || size === null ? "" : size);
|
|
342
|
-
//
|
|
343
|
-
//
|
|
349
|
+
// THE SAME REQUEST - A POLL IS ALREADY RUNNING: return the last snapshot, do not create a second subscription.
|
|
350
|
+
// Otherwise every screen tick would reset the core state and briefly serve an empty book to a direct reader.
|
|
344
351
|
if (bookStop && bookKey === key) return bookCore;
|
|
345
|
-
if (bookStop) { try { bookStop(); } catch { /*
|
|
352
|
+
if (bookStop) { try { bookStop(); } catch { /* already removed */ } bookStop = null; }
|
|
346
353
|
bookKey = key;
|
|
347
354
|
bookResume = null;
|
|
348
355
|
const wait = new Promise((resolve) => { bookResume = resolve; });
|
|
@@ -354,15 +361,15 @@ export async function sdkBook({ chain, direction, token, size } = {}) {
|
|
|
354
361
|
} catch (error) {
|
|
355
362
|
bookResume = null;
|
|
356
363
|
bookCore = null;
|
|
357
|
-
console.warn("[bridge]
|
|
358
|
-
"):
|
|
364
|
+
console.warn("[bridge] the quote book was not served to the core (" + ((error && error.message) || error) +
|
|
365
|
+
"): there will be no offers; see www/js/sdk/bridge.js");
|
|
359
366
|
return null;
|
|
360
367
|
}
|
|
361
368
|
await wait;
|
|
362
369
|
return bookCore;
|
|
363
370
|
}
|
|
364
371
|
|
|
365
|
-
//
|
|
372
|
+
// THE LAST SNAPSHOT WITHOUT WAITING - in the screen's shape. The core has not been polled once - empty (and that is honest).
|
|
366
373
|
export function sdkBookSnapshot() {
|
|
367
374
|
return bookOf(bookCore);
|
|
368
375
|
}
|
|
@@ -377,29 +384,29 @@ export async function sdkGetSwap(id, chainSlug) {
|
|
|
377
384
|
return ctx ? ctx.sdk.swaps.get(id) : null;
|
|
378
385
|
}
|
|
379
386
|
|
|
380
|
-
//
|
|
381
|
-
//
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
//
|
|
385
|
-
// (core/finality.js, orderWindows),
|
|
386
|
-
//
|
|
387
|
+
// ORDER TERMS - DATA FOR THE CORE, NOT ITS RULES.
|
|
388
|
+
// The core requires these eight fields FROM OUTSIDE (sdk/index.d.ts, StartRequest.order) and refuses without them:
|
|
389
|
+
// both the DLEQ proof and the firm-quote signature are bound to them (atomic/orderContext.js, FIELDS). Here they
|
|
390
|
+
// are not derived again but taken from the same sources the page used: network and factory from the network
|
|
391
|
+
// registry, the depositor - the connected wallet, the amount - from the quote, the windows - from the provider's
|
|
392
|
+
// finality policy (core/finality.js, orderWindows), the salt - from the engine's generator (evm/funding.js,
|
|
393
|
+
// newSecret). No windows or numbers of its own appear here: the minimum-window rule lives in core/finality.js and core/preSignGuards.js.
|
|
387
394
|
export function sdkOrderTerms({ chain, amountWei, finality = null, salt = null, asset = "XMR" } = {}) {
|
|
388
395
|
const windows = orderWindows(finality);
|
|
389
396
|
const nowSec = Math.floor(Date.now() / 1000);
|
|
390
397
|
const escrow = (chain && chain.escrow) || {};
|
|
391
|
-
//
|
|
392
|
-
//
|
|
393
|
-
if (!escrow.cashier) throw new Error("
|
|
398
|
+
// THE FEE CASHIER IS PART OF THE ORDER TERMS, like the factory: it comes from the network registry, not from
|
|
399
|
+
// the contract. Without it the order cannot be assembled: the term is mandatory and enters termsHash.
|
|
400
|
+
if (!escrow.cashier) throw new Error("no fee cashier set on this network (escrow.cashier) - the order cannot be assembled");
|
|
394
401
|
return {
|
|
395
402
|
chainId: chain.chainId,
|
|
396
403
|
factory: escrow.address,
|
|
397
404
|
cashier: escrow.cashier,
|
|
398
405
|
locker: evm.address(),
|
|
399
406
|
amount: String(amountWei),
|
|
400
|
-
//
|
|
401
|
-
//
|
|
402
|
-
//
|
|
407
|
+
// WHAT THE PERSON RECEIVES. The field is not part of the canonical order context (it is a consequence of the
|
|
408
|
+
// pair and network), but the provider expects it - by it he understands the payout is in XMR, and puts it in
|
|
409
|
+
// his quote record. The value comes as data from the screen; the default is XMR (the screen buying XMR for the native coin).
|
|
403
410
|
asset: String(asset || "XMR"),
|
|
404
411
|
readyBy: String(nowSec + windows.readyWindowSeconds),
|
|
405
412
|
t1: String(nowSec + windows.claimWindowSeconds),
|
|
@@ -407,13 +414,13 @@ export function sdkOrderTerms({ chain, amountWei, finality = null, salt = null,
|
|
|
407
414
|
};
|
|
408
415
|
}
|
|
409
416
|
|
|
410
|
-
//
|
|
411
|
-
//
|
|
412
|
-
//
|
|
417
|
+
// A FIRM QUOTE FOR THE ORDER - BEFORE SIGNING. The screen shows the fee rate and recipient BEFORE the person
|
|
418
|
+
// signs, and hands THE SAME quote to the swap start (sdkStartSwap, field orderQuote): exactly what is shown is
|
|
419
|
+
// signed, and no second request to the node is made.
|
|
413
420
|
//
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
//
|
|
421
|
+
// WHY THIS PLACE AND NOT THE SCREEN. The order terms (network, factory, depositor, amount, windows, salt) are
|
|
422
|
+
// assembled in ONE place - sdkOrderTerms; the screen must not assemble them in a second edition. Here they are
|
|
423
|
+
// assembled, a firm quote is requested by them through the core's path, and both go outward: `order` and `quote`.
|
|
417
424
|
export async function sdkOrderQuote({ chain, providerId, amountWei, finality = null, salt = null, asset = "XMR" } = {}) {
|
|
418
425
|
const ctx = await instanceFor(chain);
|
|
419
426
|
if (!ctx) return null;
|
|
@@ -422,79 +429,82 @@ export async function sdkOrderQuote({ chain, providerId, amountWei, finality = n
|
|
|
422
429
|
return { order, quote };
|
|
423
430
|
}
|
|
424
431
|
|
|
425
|
-
//
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
//
|
|
432
|
+
// STARTING THE SWAP WHOLE, BY THE CORE. Step order, the order side, deadlines into the contract, the escrow
|
|
433
|
+
// address FROM THE RECEIPT, our readiness mark and watching the XMR - all of it is held by the core
|
|
434
|
+
// (sdk/src/swaps.mjs, swaps.start). The screen passes only data: the quote, where to receive, the password, the
|
|
435
|
+
// wallet and the file-confirmation handler. The page assembles no order side, no addresses and no transactions here.
|
|
429
436
|
export async function sdkStartSwap(request) {
|
|
437
|
+
// THE CHECK SEAM (see useStartSwap above): a stand-in for the escrow funding while the asynchronous path is
|
|
438
|
+
// exercised. Absent in production - the real core path below is what runs.
|
|
439
|
+
if (startSwapOverride) return startSwapOverride({ ...(request || {}) });
|
|
430
440
|
const ctx = await instanceFor(request && request.chain);
|
|
431
441
|
if (!ctx) return null;
|
|
432
442
|
const req = { ...(request || {}) };
|
|
433
|
-
//
|
|
434
|
-
//
|
|
443
|
+
// THE WALLET FOR THE LOCK - THE PAGE WALLET ADAPTER, IF THE CALLER DID NOT BRING ONE. Signing is possible only
|
|
444
|
+
// in the page's wallet provider, and the core has no provider of its own: the core gets a ready adapter (send/receipt).
|
|
435
445
|
if (!req.wallet) {
|
|
436
446
|
const mods = await sdkCoreModules();
|
|
437
447
|
const wallet = mods ? walletFor(mods) : null;
|
|
438
448
|
if (wallet) req.wallet = wallet;
|
|
439
449
|
}
|
|
440
|
-
//
|
|
441
|
-
//
|
|
442
|
-
// (
|
|
443
|
-
//
|
|
450
|
+
// THE PAGE WALLET IS ALSO GIVEN TO THE CORE AS ITS WALLET: the network guards (preflight) ask the network OF
|
|
451
|
+
// THE CORE'S WALLET, not of the one passed for the lock - otherwise the start fails with the code network
|
|
452
|
+
// { wallet-unknown } (the live Node run does the same: sdk.wallet.use(...); await sdk.wallet.connect()). The
|
|
453
|
+
// signature does not change: both connecting and sending go through the same page provider.
|
|
444
454
|
if (req.wallet) {
|
|
445
455
|
try { ctx.sdk.wallet.use(req.wallet); await ctx.sdk.wallet.connect({ chainId: ctx.chain.chainId }); }
|
|
446
|
-
catch { /*
|
|
456
|
+
catch { /* the wallet did not come up - the core itself will name the refusal (network/wallet-unknown), no silence */ }
|
|
447
457
|
}
|
|
448
|
-
//
|
|
449
|
-
//
|
|
458
|
+
// No order terms - assemble them from data (see sdkOrderTerms). The StartRequest contract also allows ready
|
|
459
|
+
// ones: then the caller brings its own order side with its own points (record injection).
|
|
450
460
|
if (!req.order) {
|
|
451
461
|
req.order = sdkOrderTerms({ chain: ctx.chain, amountWei: req.amountWei, finality: req.finality,
|
|
452
462
|
salt: req.salt, asset: req.receiveAsset });
|
|
453
463
|
}
|
|
454
|
-
//
|
|
455
|
-
//
|
|
456
|
-
//
|
|
464
|
+
// A FIRM QUOTE FOR THIS ORDER - AND IT ALSO GOES INTO THE LOCK. A screen that showed the fee BEFORE signing
|
|
465
|
+
// brings the quote READY-MADE (sdkOrderQuote) - then we do not go to the node again and exactly what the person
|
|
466
|
+
// saw is signed. If it did not, we request it here through the core's path (config.route("orderQuote")).
|
|
457
467
|
//
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
//
|
|
468
|
+
// WHY THIS SEPARATE FIELD. The lock takes the quote NOT from req.quote: req.quote is the book's indicative
|
|
469
|
+
// quote for the guards (freshness, deadlines), while the factory needs a SIGNED SET (fee, registry, provider).
|
|
470
|
+
// The core reads it as `request.orderQuote` (sdk/src/swaps.mjs). While the bridge did not put it there, the
|
|
471
|
+
// start reached the deposit and failed there: "a signed quote is required: the factory takes a quote, not bare order terms".
|
|
462
472
|
if (!req.orderQuote && req.providerId) {
|
|
463
473
|
req.orderQuote = await ctx.sdk.quotes.firm({ providerId: req.providerId, order: req.order });
|
|
464
474
|
}
|
|
465
475
|
if (req.orderQuote) {
|
|
466
|
-
//
|
|
467
|
-
// (
|
|
476
|
+
// THE CLAIMER IS NAMED BY THE PROVIDER, and enters the order context: without it the proof would not agree
|
|
477
|
+
// (the core refuses - context mismatch). Here we only carry its value into the terms.
|
|
468
478
|
if (req.orderQuote.claimer) req.order = { ...req.order, claimer: req.orderQuote.claimer };
|
|
469
|
-
// ID
|
|
470
|
-
//
|
|
471
|
-
//
|
|
479
|
+
// THE ORDER QUOTE ID GOES INTO THE DEAL RECORD: by it our service ties the escrow to the provider node's
|
|
480
|
+
// record, and only then can the node take the ETH. The screen did it itself (swap.orderQuoteId) - so the data
|
|
481
|
+
// stays the same, and it must not be lost in translation.
|
|
472
482
|
if (req.orderQuote.id) req.quote = { ...(req.quote || {}), id: req.orderQuote.id };
|
|
473
|
-
//
|
|
474
|
-
//
|
|
483
|
+
// THE COUNTERPARTY SIDE IS THIS SAME QUOTE: it holds the provider's half, point and proof, and the core
|
|
484
|
+
// checks it too (order.acceptCounterparty). The bridge invents no counterparty side of its own.
|
|
475
485
|
if (!req.counterparty) req.counterparty = req.orderQuote;
|
|
476
486
|
}
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
//
|
|
487
|
+
// THE ORDER DEADLINES ALSO GO INTO THE QUOTE: the deadline guards (preflight -> deadlineVerdict) read readyBy/t1
|
|
488
|
+
// FROM THE QUOTE, not from the terms. The values are THE SAME as those that went into order - no second count
|
|
489
|
+
// and no second opinion; otherwise the core honestly refuses with deadline { kind: "deadlines-unstated" }.
|
|
480
490
|
req.quote = { ...(req.quote || {}), readyBy: Number(req.order.readyBy), t1: Number(req.order.t1) };
|
|
481
491
|
return ctx.sdk.swaps.start(req);
|
|
482
492
|
}
|
|
483
493
|
|
|
484
|
-
//
|
|
485
|
-
//
|
|
486
|
-
//
|
|
494
|
+
// WATCHING THE XMR ARRIVAL - THE SAME CORE STEP AS THE START (GET /api/swaps/{id}). The separate function is
|
|
495
|
+
// needed by state screens: they wait for the arrival rather than starting a swap. The order expectations and the
|
|
496
|
+
// wallet are passed by the caller - without them the core does not sign the readiness mark, only names its next step.
|
|
487
497
|
export async function sdkWatchSwap(request) {
|
|
488
498
|
const ctx = await instanceFor(request && request.chain);
|
|
489
499
|
if (!ctx) return null;
|
|
490
500
|
return ctx.sdk.swaps.watch(request);
|
|
491
501
|
}
|
|
492
502
|
|
|
493
|
-
// ---
|
|
494
|
-
//
|
|
495
|
-
//
|
|
496
|
-
//
|
|
497
|
-
//
|
|
503
|
+
// --- THE DEAL LIST FROM THE CORE (the #/swaps screen) ---------------------------------------------
|
|
504
|
+
// READING, MERGING AND DROPPING GO THROUGH THE CORE, NOT THE ENGINE ON THE PAGE. sdkListSwaps above returns
|
|
505
|
+
// deal states (swaps.list); below is the server list (swaps.sync: the path and merge rule live in the core) and
|
|
506
|
+
// record dropping (swaps.forget: it removes the record only here; the server and the contract keep everything).
|
|
507
|
+
// The core did not come up - null, and the console names the cause (see sdkBundle), not silence.
|
|
498
508
|
export async function sdkSyncSwaps(chainSlug) {
|
|
499
509
|
const ctx = await instanceFor(chainSlug);
|
|
500
510
|
return ctx ? ctx.sdk.swaps.sync() : null;
|
|
@@ -505,46 +515,46 @@ export async function sdkForgetSwap(id, chainSlug) {
|
|
|
505
515
|
return ctx ? ctx.sdk.swaps.forget(id) : null;
|
|
506
516
|
}
|
|
507
517
|
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
//
|
|
511
|
-
//
|
|
512
|
-
//
|
|
518
|
+
// WATCHING AND PAGE READS - THROUGH THE SAME SEAM, UNDER THE FORMER NAMES. The screen declares the poll focus and
|
|
519
|
+
// reads the fee rate (the reference panel) HERE, not from core/ and evm/ directly. The names are left VERBATIM as
|
|
520
|
+
// the engine's (the same technique as markReadyOrder/claimOrder/refundOrder above): the screen changes the import
|
|
521
|
+
// SOURCE, not the call expression. The order state (orderStatus/orderDeadlines) is declared as functions above -
|
|
522
|
+
// the same reads, but the reading rules now live in the package.
|
|
513
523
|
export { setLiveFocus, cachedFeeRate, dealSwapIds, serverRestoreHeightFor, STEP_LABELS };
|
|
514
524
|
|
|
515
|
-
//
|
|
516
|
-
//
|
|
517
|
-
//
|
|
518
|
-
//
|
|
519
|
-
//
|
|
525
|
+
// THE ORDER STATE AND ITS DEADLINES - CHAIN READS WITH THE PAGE'S WALLET, BUT THROUGH THE CORE. The reading rules
|
|
526
|
+
// themselves (status()/t1()/termsHash()/readyBy() and answer parsing) moved into the package
|
|
527
|
+
// (sdk/src/swap-flow.mjs, the order.status/order.deadlines facade). The shim exposes them to the screen UNDER THE
|
|
528
|
+
// FORMER NAMES, and the reader wallet it hands the core is the same as for the order actions (optionsFor ->
|
|
529
|
+
// evmCall), so it reads the same wallet that will sign. The core did not load - a NAMED refusal, not an empty state.
|
|
520
530
|
export async function orderStatus(escrow) {
|
|
521
531
|
const ctx = await instanceFor(undefined);
|
|
522
|
-
if (!ctx) throw new Error("[bridge]
|
|
532
|
+
if (!ctx) throw new Error("[bridge] cannot read the order state: the SDK core was not served to the page");
|
|
523
533
|
return ctx.sdk.order.status(escrow);
|
|
524
534
|
}
|
|
525
535
|
|
|
526
536
|
export async function orderDeadlines(escrow) {
|
|
527
537
|
const ctx = await instanceFor(undefined);
|
|
528
|
-
if (!ctx) throw new Error("[bridge]
|
|
538
|
+
if (!ctx) throw new Error("[bridge] cannot read the order deadlines: the SDK core was not served to the page");
|
|
529
539
|
return ctx.sdk.order.deadlines(escrow);
|
|
530
540
|
}
|
|
531
541
|
|
|
532
|
-
//
|
|
533
|
-
//
|
|
542
|
+
// THE MONERO NODE HEIGHT - A PAGE READ. The core has no node (all chain reads go through the page's wallet
|
|
543
|
+
// adapter), so the height for the scan height is taken here, not invented. The name is kept (nodeHeight).
|
|
534
544
|
export async function nodeHeight() { return nodeHeightValue(); }
|
|
535
545
|
|
|
536
|
-
// ---
|
|
537
|
-
//
|
|
538
|
-
//
|
|
539
|
-
//
|
|
546
|
+
// --- THE DEMO DEAL STATE AND ACTIONS (the progress screen, progress.js) ---------------------------
|
|
547
|
+
// THE STATE COMES FROM THE CORE: swaps.progress assembles a deal snapshot (record + state output + wallet from halves).
|
|
548
|
+
// The screen has NO former engine road (unlike the order actions above): the core did not come up - null, and the
|
|
549
|
+
// screen honestly says there is no state. The list screen is built the same way (sdkListSwaps).
|
|
540
550
|
export async function sdkProgress(id, chainSlug) {
|
|
541
551
|
const ctx = await instanceFor(chainSlug);
|
|
542
552
|
return ctx ? ctx.sdk.swaps.progress(id) : null;
|
|
543
553
|
}
|
|
544
554
|
|
|
545
|
-
//
|
|
546
|
-
//
|
|
547
|
-
// setDestination),
|
|
555
|
+
// THE DEMO DEAL ACTIONS AND RECORD - through the core, with the former engine call as a fallback: they are THE SAME
|
|
556
|
+
// functions (sdk/src/swaps.mjs calls engine.swap.*). The names are the core's (swaps.confirmReady/refundEth/sweepNow/
|
|
557
|
+
// setDestination), not the screen's call strings.
|
|
548
558
|
export async function sdkConfirmReady(id) {
|
|
549
559
|
const ctx = await instanceFor(undefined);
|
|
550
560
|
if (ctx) return ctx.sdk.swaps.confirmReady(id);
|
|
@@ -572,31 +582,31 @@ export async function sdkSetDestination(id, address) {
|
|
|
572
582
|
return engineSaveSwap(swap);
|
|
573
583
|
}
|
|
574
584
|
|
|
575
|
-
//
|
|
576
|
-
//
|
|
585
|
+
// THE MONERO ADDRESS NETWORK - A CORE SURFACE (it owns the address format): the shim only exposes it to the screen.
|
|
586
|
+
// The fallback is the same module that mirrors the core (www/js/monero/address.js): there is no second prefix table.
|
|
577
587
|
export async function sdkAddressNetwork(address) {
|
|
578
588
|
const ctx = await instanceFor(undefined);
|
|
579
589
|
if (ctx) return ctx.sdk.swaps.addressNetwork(address);
|
|
580
590
|
try { return networkFromShape(address); } catch { return null; }
|
|
581
591
|
}
|
|
582
592
|
|
|
583
|
-
// ---
|
|
584
|
-
//
|
|
585
|
-
//
|
|
586
|
-
// * evm, swapCore, moneroNode -
|
|
587
|
-
//
|
|
588
|
-
// *
|
|
589
|
-
//
|
|
590
|
-
// * networkFromShape/networkLabel -
|
|
591
|
-
//
|
|
592
|
-
// * createOrderWorker -
|
|
593
|
-
//
|
|
594
|
-
// * createSwap/createReverseSwap/activeSwaps -
|
|
595
|
-
//
|
|
596
|
-
// * createSwapWallet -
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
//
|
|
593
|
+
// --- THE PAGE SHOWCASE AND MECHANISMS: FORM, SIGNING, SALE, FOUNDATION ----------------------------
|
|
594
|
+
// HERE LIVES WHAT SCREENS TOOK FROM THE ENGINE DIRECTLY and now take through THE SAME SEAM - under the same names.
|
|
595
|
+
// This is deliberately kept and named, not forgotten:
|
|
596
|
+
// * evm, swapCore, moneroNode - PAGE mechanisms: the wallet (signing is possible only in its provider),
|
|
597
|
+
// the deal digest and the poll tick, reads and polling of the Monero node (the core has no node);
|
|
598
|
+
// * prices, fees, gas and the form's DEX leg - SHOWCASE: the numbers are read from the chain by engine
|
|
599
|
+
// modules, and the screen gets them through the seam, not by a second road into the engine;
|
|
600
|
+
// * networkFromShape/networkLabel - the Monero address shape and its name: the same format module the core
|
|
601
|
+
// mirrors (there is no second prefix table);
|
|
602
|
+
// * createOrderWorker - the atomic-swap halves worker: the cryptography lives in one place and is called by a
|
|
603
|
+
// worker so the main thread does not freeze;
|
|
604
|
+
// * createSwap/createReverseSwap/activeSwaps - the RECORD of the demo and reverse deal (the record is kept by
|
|
605
|
+
// the engine; the core exposes its STATE via swaps.list/swaps.progress).
|
|
606
|
+
// * createSwapWallet - THE FORM'S DEAL WALLET (state between screens, ui/formState.js): the page wallet with
|
|
607
|
+
// its own keys. The core does not need it, so the seam exposes it with the same import as the rest.
|
|
608
|
+
// THE NAME IS TAKEN FROM THE ENGINE HERE (by import) AND EXPOSED OUTWARD (by export) - one seam, one copy. No
|
|
609
|
+
// new rule here: the screen changes the import source, not the call expression.
|
|
600
610
|
import { networkLabel, probeMode, createSwapWallet } from "../monero/wallet.js";
|
|
601
611
|
import { amountInputValue } from "../evm/amounts.js";
|
|
602
612
|
import { refreshChainPrices, priceLabel } from "../evm/prices.js";
|