@ninsei-labs/sdk 0.39.0 → 0.39.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 +15 -0
- package/engine/core/chainSource.js +306 -306
- package/engine/core/sellWindow.js +43 -43
- package/engine/core/swap.js +1153 -1153
- package/engine/evm/claimGas.js +87 -87
- package/engine/evm/dex.js +836 -836
- package/engine/evm/gasReserve.js +88 -88
- package/engine/evm/prices.js +179 -179
- package/package.json +1 -1
- package/src/actions.mjs +72 -72
- package/src/adapters/node-test-evm-wallet.mjs +345 -345
- package/src/engine.mjs +53 -53
- package/src/lock.mjs +140 -140
- package/src/order.mjs +212 -212
- package/src/quotes.mjs +465 -465
- package/src/swaps.mjs +935 -935
- package/src/xmr-arrival.mjs +289 -289
package/engine/evm/claimGas.js
CHANGED
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
// GENERATED FILE - a byte-for-byte copy of the engine module www/js/evm/claimGas.js for the SDK package.
|
|
2
|
-
// Edit the source under www/js, then run: node tools/build-sdk-engine.mjs
|
|
3
|
-
// tools/check-sdk-engine.mjs reddens on any drift, so a stale copy cannot ship silently.
|
|
4
|
-
// Everything below this header is identical to the source.
|
|
5
|
-
|
|
6
|
-
// ГАЗ ЗАБОРА ПРИ ПРОДАЖЕ XMR (claim): ОДИН ИСТОЧНИК ПРАВДЫ ДЛЯ КЛИЕНТА И ДЛЯ НОДЫ (issue #127).
|
|
7
|
-
//
|
|
8
|
-
// СУТЬ. В обратном обмене человек отдаёт XMR и забирает ETH вызовом `claim` в сети расчёта. Своего ETH у
|
|
9
|
-
// него нет, поэтому газ на claim ПРИСЫЛАЕТ НОДА (issue #78, rfq/reverseGas.mjs). Но правила газа жили в
|
|
10
|
-
// ДВУХ местах: страница/SDK отправляли claim с пределом 250 000 и комиссией `2 x baseFee + 1 gwei`
|
|
11
|
-
// (движок сделки теперь в пакете: sdk/src/swap-flow.mjs; www/js/evm/session.js), а нода считала подарок как `eth_gasPrice x 120 000`
|
|
12
|
-
// (rfq/reverseGas.mjs). Числа расходились примерно в 100 раз, и человек с одним подарком claim отправить
|
|
13
|
-
// не мог: узел принимает транзакцию, только если на балансе есть `gasLimit x maxFeePerGas`, а подарка на
|
|
14
|
-
// это не хватало. Теперь оба числа считает ЭТОТ модуль.
|
|
15
|
-
//
|
|
16
|
-
// ПОЧЕМУ ОТДЕЛЬНЫЙ МОДУЛЬ И ПОЧЕМУ ПОД www/js. Формула обязана быть ОДНА. Её читает и страница/SDK
|
|
17
|
-
// (движок живёт под www/js), и нода - rfq/reverseGas.mjs, а rfq уже импортирует из www/js (см.
|
|
18
|
-
// rfq/payoutFee.mjs, `../www/js/core/format.js`). Обратный импорт невозможен: боевой веб-корень - www/,
|
|
19
|
-
// каталог rfq/ браузеру не отдаётся. Поэтому единственный общий дом - www/js/evm/.
|
|
20
|
-
//
|
|
21
|
-
// ЧТО ЗДЕСЬ ОДНО. Предел газа claim, правило комиссии (2 x baseFee + чаевые) и РАЗМЕР ПОДАРКА - та же
|
|
22
|
-
// стоимость claim плюс ЯВНЫЙ ЗАПАС на рост базовой цены между выдачей билета и забором. Второго расчёта
|
|
23
|
-
// размера подарка нет ни у ноды, ни у прогонов: они зовут claimGasGiftWei отсюда.
|
|
24
|
-
|
|
25
|
-
// ПРЕДЕЛ ГАЗА CLAIM - ОДНО ЧИСЛО НА ОБЕИХ СТОРОНАХ. Это тот же предел, с которым нода подписывает свой
|
|
26
|
-
// claim в rfq/payout.mjs, и тот же, что отправляет страница/SDK (sdk/src/swap-flow.mjs). Число не
|
|
27
|
-
// выдумано: живой прогон меряет фактический gasUsed забора сверху (tools/live-gas-run.mjs).
|
|
28
|
-
export const CLAIM_GAS_LIMIT = 120_000n;
|
|
29
|
-
|
|
30
|
-
// ПОЛ ЧАЕВЫХ - ПОЛИТИКА СЕТИ, А НЕ КОНСТАНТА В КОДЕ ОТПРАВКИ. Раньше session.js ставил минимум 1 gwei
|
|
31
|
-
// ВСЕГДА. На сети с дешёвым газом (Arbitrum One: baseFee ~0.02 gwei) это раздувало maxFeePerGas примерно
|
|
32
|
-
// в 50 раз и поднимало ТРЕБУЕМЫЙ БАЛАНС пропорционально - то есть ломало ровно того, кому газ и
|
|
33
|
-
// предназначен. Для Arbitrum чаевые не нужны: пол 0. Сеть со своей политикой передаёт minTipWei
|
|
34
|
-
// аргументом (session.js берёт сеть из реестра, www/js/core/config.js).
|
|
35
|
-
export const CLAIM_TIP_FLOOR_WEI = 0n;
|
|
36
|
-
|
|
37
|
-
const toBig = (v) => {
|
|
38
|
-
if (v === null || v === undefined || v === "") return null;
|
|
39
|
-
try { return BigInt(typeof v === "bigint" ? v : String(v)); } catch { return null; }
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
// КОМИССИЯ ЗАБОРА (EIP-1559): `maxFeePerGas = 2 x baseFee + чаевые`. Удвоение базовой цены перекрывает её
|
|
43
|
-
// рост за время подтверждения СВОЕЙ транзакции; чаевые - это разница gasPrice - baseFee (её отдаёт любая
|
|
44
|
-
// цепь), не ниже пола сети. baseFee = 0 (сеть без EIP-1559) - полей комиссии нет вовсе, и это null, а не
|
|
45
|
-
// ноль: неизвестное обязано называться, а не выдаваться за измеренное.
|
|
46
|
-
export function claimMaxFeePerGasWei({ baseFeeWei, priorityFeeWei = 0n, minTipWei = CLAIM_TIP_FLOOR_WEI } = {}) {
|
|
47
|
-
const base = toBig(baseFeeWei);
|
|
48
|
-
if (base === null || base <= 0n) return null;
|
|
49
|
-
const prio = toBig(priorityFeeWei);
|
|
50
|
-
const floor = toBig(minTipWei);
|
|
51
|
-
const floored = floor === null || floor < 0n ? 0n : floor;
|
|
52
|
-
const tip = prio !== null && prio > floored ? prio : floored;
|
|
53
|
-
return base * 2n + tip;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// СКОЛЬКО НУЖНО НА БАЛАНСЕ ДЛЯ CLAIM - это же правило приёма транзакции узлом: `gasLimit x maxFeePerGas`.
|
|
57
|
-
// Один из множителей не измерен - null (не «ноль газа»).
|
|
58
|
-
export function claimRequiredWei({ gasLimit = CLAIM_GAS_LIMIT, maxFeePerGasWei } = {}) {
|
|
59
|
-
const limit = toBig(gasLimit);
|
|
60
|
-
const maxFee = toBig(maxFeePerGasWei);
|
|
61
|
-
if (limit === null || limit <= 0n || maxFee === null || maxFee <= 0n) return null;
|
|
62
|
-
return limit * maxFee;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ЗАПАС НА РОСТ БАЗОВОЙ ЦЕНЫ МЕЖДУ ВЫДАЧЕЙ БИЛЕТА И ЗАБОРОМ, в базисных пунктах (10 000 = +100%).
|
|
66
|
-
//
|
|
67
|
-
// ПОЧЕМУ ОН НУЖЕН И ПОЧЕМУ СТОЛЬКО. Стоимость claim считается на момент БИЛЕТА, а сам claim случается
|
|
68
|
-
// позже: билет живёт RFQ_ORDER_QUOTE_TTL_MS, по умолчанию 40 минут (rfq/config.mjs). Правило клиента
|
|
69
|
-
// (2 x baseFee) перекрывает рост цены ТОЛЬКО на время подтверждения своей транзакции, а не эти 40 минут.
|
|
70
|
-
// Подарок без запаса не проходит, если базовая цена хоть немного поднялась с момента билета - это и
|
|
71
|
-
// показал issue #127. +100% перекрывает УДВОЕНИЕ базовой цены за окно билета, то есть подарок остаётся
|
|
72
|
-
// достаточным, даже если цена газа к забору вырастет вдвое. Значение - настройка ноды
|
|
73
|
-
// (RFQ_REVERSE_GAS_RESERVE_BPS), а не догадка: её видно и можно переопределить без правки кода.
|
|
74
|
-
export const DEFAULT_GIFT_RESERVE_BPS = 10_000n;
|
|
75
|
-
|
|
76
|
-
// РАЗМЕР ПОДАРКА - ТА ЖЕ стоимость claim, что требует клиент, ПЛЮС запас. Это ЕДИНСТВЕННЫЙ расчёт размера
|
|
77
|
-
// подарка: нода (rfq/reverseGas.mjs, requiredGasWei) и живой прогон зовут ИМЕННО ЕГО, а не свою копию.
|
|
78
|
-
// base берётся у цепи на момент билета; priorityFeeWei - реальные чаевые сети (gasPrice - baseFee), если
|
|
79
|
-
// известны. Нечитаемая база - null, а не ноль.
|
|
80
|
-
export function claimGasGiftWei({ baseFeeWei, priorityFeeWei, minTipWei, gasLimit = CLAIM_GAS_LIMIT, reserveBps = DEFAULT_GIFT_RESERVE_BPS } = {}) {
|
|
81
|
-
const maxFee = claimMaxFeePerGasWei({ baseFeeWei, priorityFeeWei, minTipWei });
|
|
82
|
-
const need = claimRequiredWei({ gasLimit, maxFeePerGasWei: maxFee });
|
|
83
|
-
if (need === null) return null;
|
|
84
|
-
const bps = toBig(reserveBps);
|
|
85
|
-
const step = bps === null || bps < 0n ? 0n : bps;
|
|
86
|
-
return need + (need * step) / 10_000n;
|
|
87
|
-
}
|
|
1
|
+
// GENERATED FILE - a byte-for-byte copy of the engine module www/js/evm/claimGas.js for the SDK package.
|
|
2
|
+
// Edit the source under www/js, then run: node tools/build-sdk-engine.mjs
|
|
3
|
+
// tools/check-sdk-engine.mjs reddens on any drift, so a stale copy cannot ship silently.
|
|
4
|
+
// Everything below this header is identical to the source.
|
|
5
|
+
|
|
6
|
+
// ГАЗ ЗАБОРА ПРИ ПРОДАЖЕ XMR (claim): ОДИН ИСТОЧНИК ПРАВДЫ ДЛЯ КЛИЕНТА И ДЛЯ НОДЫ (issue #127).
|
|
7
|
+
//
|
|
8
|
+
// СУТЬ. В обратном обмене человек отдаёт XMR и забирает ETH вызовом `claim` в сети расчёта. Своего ETH у
|
|
9
|
+
// него нет, поэтому газ на claim ПРИСЫЛАЕТ НОДА (issue #78, rfq/reverseGas.mjs). Но правила газа жили в
|
|
10
|
+
// ДВУХ местах: страница/SDK отправляли claim с пределом 250 000 и комиссией `2 x baseFee + 1 gwei`
|
|
11
|
+
// (движок сделки теперь в пакете: sdk/src/swap-flow.mjs; www/js/evm/session.js), а нода считала подарок как `eth_gasPrice x 120 000`
|
|
12
|
+
// (rfq/reverseGas.mjs). Числа расходились примерно в 100 раз, и человек с одним подарком claim отправить
|
|
13
|
+
// не мог: узел принимает транзакцию, только если на балансе есть `gasLimit x maxFeePerGas`, а подарка на
|
|
14
|
+
// это не хватало. Теперь оба числа считает ЭТОТ модуль.
|
|
15
|
+
//
|
|
16
|
+
// ПОЧЕМУ ОТДЕЛЬНЫЙ МОДУЛЬ И ПОЧЕМУ ПОД www/js. Формула обязана быть ОДНА. Её читает и страница/SDK
|
|
17
|
+
// (движок живёт под www/js), и нода - rfq/reverseGas.mjs, а rfq уже импортирует из www/js (см.
|
|
18
|
+
// rfq/payoutFee.mjs, `../www/js/core/format.js`). Обратный импорт невозможен: боевой веб-корень - www/,
|
|
19
|
+
// каталог rfq/ браузеру не отдаётся. Поэтому единственный общий дом - www/js/evm/.
|
|
20
|
+
//
|
|
21
|
+
// ЧТО ЗДЕСЬ ОДНО. Предел газа claim, правило комиссии (2 x baseFee + чаевые) и РАЗМЕР ПОДАРКА - та же
|
|
22
|
+
// стоимость claim плюс ЯВНЫЙ ЗАПАС на рост базовой цены между выдачей билета и забором. Второго расчёта
|
|
23
|
+
// размера подарка нет ни у ноды, ни у прогонов: они зовут claimGasGiftWei отсюда.
|
|
24
|
+
|
|
25
|
+
// ПРЕДЕЛ ГАЗА CLAIM - ОДНО ЧИСЛО НА ОБЕИХ СТОРОНАХ. Это тот же предел, с которым нода подписывает свой
|
|
26
|
+
// claim в rfq/payout.mjs, и тот же, что отправляет страница/SDK (sdk/src/swap-flow.mjs). Число не
|
|
27
|
+
// выдумано: живой прогон меряет фактический gasUsed забора сверху (tools/live-gas-run.mjs).
|
|
28
|
+
export const CLAIM_GAS_LIMIT = 120_000n;
|
|
29
|
+
|
|
30
|
+
// ПОЛ ЧАЕВЫХ - ПОЛИТИКА СЕТИ, А НЕ КОНСТАНТА В КОДЕ ОТПРАВКИ. Раньше session.js ставил минимум 1 gwei
|
|
31
|
+
// ВСЕГДА. На сети с дешёвым газом (Arbitrum One: baseFee ~0.02 gwei) это раздувало maxFeePerGas примерно
|
|
32
|
+
// в 50 раз и поднимало ТРЕБУЕМЫЙ БАЛАНС пропорционально - то есть ломало ровно того, кому газ и
|
|
33
|
+
// предназначен. Для Arbitrum чаевые не нужны: пол 0. Сеть со своей политикой передаёт minTipWei
|
|
34
|
+
// аргументом (session.js берёт сеть из реестра, www/js/core/config.js).
|
|
35
|
+
export const CLAIM_TIP_FLOOR_WEI = 0n;
|
|
36
|
+
|
|
37
|
+
const toBig = (v) => {
|
|
38
|
+
if (v === null || v === undefined || v === "") return null;
|
|
39
|
+
try { return BigInt(typeof v === "bigint" ? v : String(v)); } catch { return null; }
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// КОМИССИЯ ЗАБОРА (EIP-1559): `maxFeePerGas = 2 x baseFee + чаевые`. Удвоение базовой цены перекрывает её
|
|
43
|
+
// рост за время подтверждения СВОЕЙ транзакции; чаевые - это разница gasPrice - baseFee (её отдаёт любая
|
|
44
|
+
// цепь), не ниже пола сети. baseFee = 0 (сеть без EIP-1559) - полей комиссии нет вовсе, и это null, а не
|
|
45
|
+
// ноль: неизвестное обязано называться, а не выдаваться за измеренное.
|
|
46
|
+
export function claimMaxFeePerGasWei({ baseFeeWei, priorityFeeWei = 0n, minTipWei = CLAIM_TIP_FLOOR_WEI } = {}) {
|
|
47
|
+
const base = toBig(baseFeeWei);
|
|
48
|
+
if (base === null || base <= 0n) return null;
|
|
49
|
+
const prio = toBig(priorityFeeWei);
|
|
50
|
+
const floor = toBig(minTipWei);
|
|
51
|
+
const floored = floor === null || floor < 0n ? 0n : floor;
|
|
52
|
+
const tip = prio !== null && prio > floored ? prio : floored;
|
|
53
|
+
return base * 2n + tip;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// СКОЛЬКО НУЖНО НА БАЛАНСЕ ДЛЯ CLAIM - это же правило приёма транзакции узлом: `gasLimit x maxFeePerGas`.
|
|
57
|
+
// Один из множителей не измерен - null (не «ноль газа»).
|
|
58
|
+
export function claimRequiredWei({ gasLimit = CLAIM_GAS_LIMIT, maxFeePerGasWei } = {}) {
|
|
59
|
+
const limit = toBig(gasLimit);
|
|
60
|
+
const maxFee = toBig(maxFeePerGasWei);
|
|
61
|
+
if (limit === null || limit <= 0n || maxFee === null || maxFee <= 0n) return null;
|
|
62
|
+
return limit * maxFee;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ЗАПАС НА РОСТ БАЗОВОЙ ЦЕНЫ МЕЖДУ ВЫДАЧЕЙ БИЛЕТА И ЗАБОРОМ, в базисных пунктах (10 000 = +100%).
|
|
66
|
+
//
|
|
67
|
+
// ПОЧЕМУ ОН НУЖЕН И ПОЧЕМУ СТОЛЬКО. Стоимость claim считается на момент БИЛЕТА, а сам claim случается
|
|
68
|
+
// позже: билет живёт RFQ_ORDER_QUOTE_TTL_MS, по умолчанию 40 минут (rfq/config.mjs). Правило клиента
|
|
69
|
+
// (2 x baseFee) перекрывает рост цены ТОЛЬКО на время подтверждения своей транзакции, а не эти 40 минут.
|
|
70
|
+
// Подарок без запаса не проходит, если базовая цена хоть немного поднялась с момента билета - это и
|
|
71
|
+
// показал issue #127. +100% перекрывает УДВОЕНИЕ базовой цены за окно билета, то есть подарок остаётся
|
|
72
|
+
// достаточным, даже если цена газа к забору вырастет вдвое. Значение - настройка ноды
|
|
73
|
+
// (RFQ_REVERSE_GAS_RESERVE_BPS), а не догадка: её видно и можно переопределить без правки кода.
|
|
74
|
+
export const DEFAULT_GIFT_RESERVE_BPS = 10_000n;
|
|
75
|
+
|
|
76
|
+
// РАЗМЕР ПОДАРКА - ТА ЖЕ стоимость claim, что требует клиент, ПЛЮС запас. Это ЕДИНСТВЕННЫЙ расчёт размера
|
|
77
|
+
// подарка: нода (rfq/reverseGas.mjs, requiredGasWei) и живой прогон зовут ИМЕННО ЕГО, а не свою копию.
|
|
78
|
+
// base берётся у цепи на момент билета; priorityFeeWei - реальные чаевые сети (gasPrice - baseFee), если
|
|
79
|
+
// известны. Нечитаемая база - null, а не ноль.
|
|
80
|
+
export function claimGasGiftWei({ baseFeeWei, priorityFeeWei, minTipWei, gasLimit = CLAIM_GAS_LIMIT, reserveBps = DEFAULT_GIFT_RESERVE_BPS } = {}) {
|
|
81
|
+
const maxFee = claimMaxFeePerGasWei({ baseFeeWei, priorityFeeWei, minTipWei });
|
|
82
|
+
const need = claimRequiredWei({ gasLimit, maxFeePerGasWei: maxFee });
|
|
83
|
+
if (need === null) return null;
|
|
84
|
+
const bps = toBig(reserveBps);
|
|
85
|
+
const step = bps === null || bps < 0n ? 0n : bps;
|
|
86
|
+
return need + (need * step) / 10_000n;
|
|
87
|
+
}
|