@vultisig/core-chain 2.29.3 → 2.31.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 +40 -0
- package/dist/Chain.d.ts +3 -0
- package/dist/Chain.d.ts.map +1 -1
- package/dist/Chain.js +1 -0
- package/dist/Chain.js.map +1 -1
- package/dist/ChainKind.d.ts +1 -0
- package/dist/ChainKind.d.ts.map +1 -1
- package/dist/ChainKind.js +1 -0
- package/dist/ChainKind.js.map +1 -1
- package/dist/chains/cosmos/thor/getThorchainTxResult.d.ts +32 -0
- package/dist/chains/cosmos/thor/getThorchainTxResult.d.ts.map +1 -0
- package/dist/chains/cosmos/thor/getThorchainTxResult.js +43 -0
- package/dist/chains/cosmos/thor/getThorchainTxResult.js.map +1 -0
- package/dist/chains/evm/chainInfo.d.ts +54 -0
- package/dist/chains/evm/chainInfo.d.ts.map +1 -1
- package/dist/chains/evm/chainInfo.js +22 -0
- package/dist/chains/evm/chainInfo.js.map +1 -1
- package/dist/chains/evm/tx/fee/index.d.ts.map +1 -1
- package/dist/chains/evm/tx/fee/index.js +1 -0
- package/dist/chains/evm/tx/fee/index.js.map +1 -1
- package/dist/coin/coinType.d.ts.map +1 -1
- package/dist/coin/coinType.js +1 -0
- package/dist/coin/coinType.js.map +1 -1
- package/dist/coin/find/resolvers/evm/index.d.ts.map +1 -1
- package/dist/coin/find/resolvers/evm/index.js +31 -2
- package/dist/coin/find/resolvers/evm/index.js.map +1 -1
- package/dist/coin/knownTokens/index.d.ts +1 -1
- package/dist/coin/knownTokens/index.d.ts.map +1 -1
- package/dist/coin/knownTokens/index.js +506 -0
- package/dist/coin/knownTokens/index.js.map +1 -1
- package/dist/coin/price/evm/getErc20Prices.d.ts.map +1 -1
- package/dist/coin/price/evm/getErc20Prices.js +1 -0
- package/dist/coin/price/evm/getErc20Prices.js.map +1 -1
- package/dist/coin/token/metadata/chains.d.ts +1 -1
- package/dist/coin/token/metadata/chains.d.ts.map +1 -1
- package/dist/security/blockaid/evmChains.d.ts.map +1 -1
- package/dist/security/blockaid/evmChains.js +2 -0
- package/dist/security/blockaid/evmChains.js.map +1 -1
- package/dist/swap/general/knownAggregatorRouters.d.ts.map +1 -1
- package/dist/swap/general/knownAggregatorRouters.js +7 -1
- package/dist/swap/general/knownAggregatorRouters.js.map +1 -1
- package/dist/swap/general/kyber/chains.d.ts +1 -1
- package/dist/swap/general/kyber/chains.d.ts.map +1 -1
- package/dist/swap/general/kyber/chains.js +1 -0
- package/dist/swap/general/kyber/chains.js.map +1 -1
- package/dist/swap/general/lifi/LifiSwapEnabledChains.d.ts +1 -1
- package/dist/swap/general/lifi/LifiSwapEnabledChains.d.ts.map +1 -1
- package/dist/swap/general/oneInch/OneInchSwapEnabledChains.d.ts +1 -1
- package/dist/swap/general/oneInch/OneInchSwapEnabledChains.d.ts.map +1 -1
- package/dist/swap/general/oneInch/OneInchSwapEnabledChains.js +3 -0
- package/dist/swap/general/oneInch/OneInchSwapEnabledChains.js.map +1 -1
- package/dist/swap/general/swapkit/api/getSwapKitQuote.d.ts.map +1 -1
- package/dist/swap/general/swapkit/api/getSwapKitQuote.js +72 -15
- package/dist/swap/general/swapkit/api/getSwapKitQuote.js.map +1 -1
- package/dist/swap/native/limitSwapCancelBucket.d.ts +47 -0
- package/dist/swap/native/limitSwapCancelBucket.d.ts.map +1 -0
- package/dist/swap/native/limitSwapCancelBucket.js +86 -0
- package/dist/swap/native/limitSwapCancelBucket.js.map +1 -0
- package/dist/swap/native/limitSwapCancelDust.d.ts +36 -0
- package/dist/swap/native/limitSwapCancelDust.d.ts.map +1 -0
- package/dist/swap/native/limitSwapCancelDust.js +100 -0
- package/dist/swap/native/limitSwapCancelDust.js.map +1 -0
- package/dist/swap/native/limitSwapCancelEligibility.d.ts +96 -0
- package/dist/swap/native/limitSwapCancelEligibility.d.ts.map +1 -0
- package/dist/swap/native/limitSwapCancelEligibility.js +165 -0
- package/dist/swap/native/limitSwapCancelEligibility.js.map +1 -0
- package/dist/swap/native/limitSwapCancelMemo.d.ts +123 -0
- package/dist/swap/native/limitSwapCancelMemo.d.ts.map +1 -0
- package/dist/swap/native/limitSwapCancelMemo.js +158 -0
- package/dist/swap/native/limitSwapCancelMemo.js.map +1 -0
- package/dist/swap/native/limitSwapMemo.d.ts.map +1 -1
- package/dist/swap/native/limitSwapMemo.js +7 -3
- package/dist/swap/native/limitSwapMemo.js.map +1 -1
- package/dist/swap/native/limitSwapOrderStatus.d.ts +23 -0
- package/dist/swap/native/limitSwapOrderStatus.d.ts.map +1 -0
- package/dist/swap/native/limitSwapOrderStatus.js +23 -0
- package/dist/swap/native/limitSwapOrderStatus.js.map +1 -0
- package/dist/swap/native/limitSwapOutcome.d.ts +61 -0
- package/dist/swap/native/limitSwapOutcome.d.ts.map +1 -0
- package/dist/swap/native/limitSwapOutcome.js +124 -0
- package/dist/swap/native/limitSwapOutcome.js.map +1 -0
- package/dist/swap/native/limitSwapQueue.d.ts +76 -0
- package/dist/swap/native/limitSwapQueue.d.ts.map +1 -0
- package/dist/swap/native/limitSwapQueue.js +175 -0
- package/dist/swap/native/limitSwapQueue.js.map +1 -0
- package/dist/swap/swapEnabledChains.d.ts +1 -1
- package/dist/swap/swapEnabledChains.d.ts.map +1 -1
- package/dist/tx/fee/evm/clampEvmPriorityFee.d.ts.map +1 -1
- package/dist/tx/fee/evm/clampEvmPriorityFee.js +2 -1
- package/dist/tx/fee/evm/clampEvmPriorityFee.js.map +1 -1
- package/dist/tx/fee/evm/evmGasLimit.d.ts.map +1 -1
- package/dist/tx/fee/evm/evmGasLimit.js +2 -0
- package/dist/tx/fee/evm/evmGasLimit.js.map +1 -1
- package/dist/utils/getBlockExplorerUrl/index.d.ts.map +1 -1
- package/dist/utils/getBlockExplorerUrl/index.js +4 -1
- package/dist/utils/getBlockExplorerUrl/index.js.map +1 -1
- package/package.json +41 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THORChain publishes `dust_threshold` in its own 1e8 fixed point, regardless
|
|
3
|
+
* of the source chain's native precision.
|
|
4
|
+
*/
|
|
5
|
+
const thorchainFixedPointDecimals = 8;
|
|
6
|
+
/**
|
|
7
|
+
* Safety multiple over the larger floor.
|
|
8
|
+
*
|
|
9
|
+
* A cancel sitting exactly ON a threshold is a coin flip: THORNode's own
|
|
10
|
+
* comparisons are not uniformly `>=`, and the published threshold can move
|
|
11
|
+
* between the inbound fetch and the transaction landing. Doubling removes both
|
|
12
|
+
* without a magic absolute floor that would be wrong on some chain's units
|
|
13
|
+
* (10,000 is dust on an 18-decimal chain and real money on an 8-decimal one).
|
|
14
|
+
*/
|
|
15
|
+
const dustSafetyMultiple = 2n;
|
|
16
|
+
/**
|
|
17
|
+
* Largest `dust_threshold`, in THORChain's own 1e8 units, that is plausible for
|
|
18
|
+
* any chain — one whole unit of the asset.
|
|
19
|
+
*
|
|
20
|
+
* `dust_threshold` is a REMOTE value that directly decides how much of the
|
|
21
|
+
* user's money is irreversibly donated: there is no refund path for anything
|
|
22
|
+
* attached to an `m=<`. So the bound has to be ABSOLUTE. A ceiling expressed as
|
|
23
|
+
* a multiple of the threshold itself cannot work — a hostile value scales both
|
|
24
|
+
* sides equally and is honoured verbatim.
|
|
25
|
+
*
|
|
26
|
+
* Real thresholds are orders of magnitude below this (Bitcoin's is 10000, or
|
|
27
|
+
* 0.0001 BTC), so the bound rejects only the absurd.
|
|
28
|
+
*/
|
|
29
|
+
const maximumThresholdIn1e8 = 100000000n;
|
|
30
|
+
/**
|
|
31
|
+
* Largest coin precision this rescaling supports.
|
|
32
|
+
*
|
|
33
|
+
* Without it, any non-negative integer is accepted and `decimals: 1000` yields
|
|
34
|
+
* a 993-digit multiplier and a meaningless amount. 36 is far above every real
|
|
35
|
+
* chain (18 is the EVM maximum) while keeping the arithmetic bounded.
|
|
36
|
+
*/
|
|
37
|
+
const maximumDecimals = 36;
|
|
38
|
+
export const limitSwapCancelDustErrors = [
|
|
39
|
+
'thresholdUnavailable',
|
|
40
|
+
'malformedThreshold',
|
|
41
|
+
'unusablePrecision',
|
|
42
|
+
'belowObservableMinimum',
|
|
43
|
+
'exceedsCeiling',
|
|
44
|
+
];
|
|
45
|
+
export class LimitSwapCancelDustError extends Error {
|
|
46
|
+
reason;
|
|
47
|
+
constructor(reason, message) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.reason = reason;
|
|
50
|
+
this.name = 'LimitSwapCancelDustError';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* How much to attach to a cancel sent FROM an L1 chain, in the source coin's
|
|
55
|
+
* smallest units.
|
|
56
|
+
*
|
|
57
|
+
* A cancel carries no value; the amount exists solely so Bifrost observes the
|
|
58
|
+
* transaction at all. Both failure modes are silent, which is why every branch
|
|
59
|
+
* here throws rather than defaulting:
|
|
60
|
+
*
|
|
61
|
+
* - Under-funded, and Bifrost drops it before it becomes a `MsgObservedTxIn` —
|
|
62
|
+
* the transaction confirms, the fee is spent, nothing is cancelled.
|
|
63
|
+
* - Over-funded, and the excess is irreversibly donated.
|
|
64
|
+
*
|
|
65
|
+
* The conversion is the part that has actually gone wrong in practice: a cancel
|
|
66
|
+
* was once signed for **2000 wei** — THORChain's 1e8-unit threshold used
|
|
67
|
+
* verbatim as an 18-decimal chain's smallest unit — which `ConvertAmount`
|
|
68
|
+
* truncates to zero. So the threshold is rescaled from 1e8 into the coin's own
|
|
69
|
+
* precision, and a result that rounds away is refused rather than nudged up to
|
|
70
|
+
* the bare observable minimum, which would be the same silent failure one order
|
|
71
|
+
* of magnitude higher.
|
|
72
|
+
*/
|
|
73
|
+
export const getLimitSwapCancelDust = ({ inbound, decimals }) => {
|
|
74
|
+
const { chain, dust_threshold: threshold } = inbound;
|
|
75
|
+
if (!threshold?.trim()) {
|
|
76
|
+
throw new LimitSwapCancelDustError('thresholdUnavailable', `cancel dust: ${chain} inbound carries no dust_threshold, so the minimum Bifrost will observe is unknown`);
|
|
77
|
+
}
|
|
78
|
+
if (!/^\d+$/.test(threshold.trim())) {
|
|
79
|
+
throw new LimitSwapCancelDustError('malformedThreshold', `cancel dust: ${chain} dust_threshold is not an integer: ${JSON.stringify(threshold)}`);
|
|
80
|
+
}
|
|
81
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > maximumDecimals) {
|
|
82
|
+
throw new LimitSwapCancelDustError('unusablePrecision', `cancel dust: ${chain} source coin declares an unusable precision (${decimals})`);
|
|
83
|
+
}
|
|
84
|
+
const thresholdIn1e8 = BigInt(threshold.trim());
|
|
85
|
+
if (thresholdIn1e8 > maximumThresholdIn1e8) {
|
|
86
|
+
throw new LimitSwapCancelDustError('exceedsCeiling', `cancel dust: ${chain} dust_threshold ${thresholdIn1e8} (1e8) exceeds the plausible ceiling ${maximumThresholdIn1e8}`);
|
|
87
|
+
}
|
|
88
|
+
// Rescale from THORChain's 1e8 into the coin's own precision. Integer-only,
|
|
89
|
+
// in a direction chosen per branch so nothing is silently lost.
|
|
90
|
+
const scaled = decimals >= thorchainFixedPointDecimals
|
|
91
|
+
? thresholdIn1e8 * 10n ** BigInt(decimals - thorchainFixedPointDecimals)
|
|
92
|
+
: thresholdIn1e8 / 10n ** BigInt(thorchainFixedPointDecimals - decimals);
|
|
93
|
+
const dust = scaled * dustSafetyMultiple;
|
|
94
|
+
if (thresholdIn1e8 > 0n && dust <= 0n) {
|
|
95
|
+
throw new LimitSwapCancelDustError('belowObservableMinimum', `cancel dust: ${chain} threshold ${thresholdIn1e8} (1e8) rounds away at ${decimals} decimals, ` +
|
|
96
|
+
'so no attachable amount would be observed');
|
|
97
|
+
}
|
|
98
|
+
return dust;
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=limitSwapCancelDust.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limitSwapCancelDust.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/native/limitSwapCancelDust.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,2BAA2B,GAAG,CAAC,CAAA;AAErC;;;;;;;;GAQG;AACH,MAAM,kBAAkB,GAAG,EAAE,CAAA;AAE7B;;;;;;;;;;;;GAYG;AACH,MAAM,qBAAqB,GAAG,UAAY,CAAA;AAE1C;;;;;;GAMG;AACH,MAAM,eAAe,GAAG,EAAE,CAAA;AAE1B,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,sBAAsB;IACtB,oBAAoB;IACpB,mBAAmB;IACnB,wBAAwB;IACxB,gBAAgB;CACR,CAAA;AAIV,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,MAAM,CAAgC;IAE/C,YAAY,MAAsC,EAAE,OAAe;QACjE,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAA;IACxC,CAAC;CACF;AASD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,EAAE,OAAO,EAAE,QAAQ,EAA+B,EAAU,EAAE;IACnG,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IAEpD,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC;QACvB,MAAM,IAAI,wBAAwB,CAChC,sBAAsB,EACtB,gBAAgB,KAAK,oFAAoF,CAC1G,CAAA;IACH,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,wBAAwB,CAChC,oBAAoB,EACpB,gBAAgB,KAAK,sCAAsC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CACvF,CAAA;IACH,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,eAAe,EAAE,CAAC;QAC9E,MAAM,IAAI,wBAAwB,CAChC,mBAAmB,EACnB,gBAAgB,KAAK,gDAAgD,QAAQ,GAAG,CACjF,CAAA;IACH,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAA;IAE/C,IAAI,cAAc,GAAG,qBAAqB,EAAE,CAAC;QAC3C,MAAM,IAAI,wBAAwB,CAChC,gBAAgB,EAChB,gBAAgB,KAAK,mBAAmB,cAAc,wCAAwC,qBAAqB,EAAE,CACtH,CAAA;IACH,CAAC;IAED,4EAA4E;IAC5E,gEAAgE;IAChE,MAAM,MAAM,GACV,QAAQ,IAAI,2BAA2B;QACrC,CAAC,CAAC,cAAc,GAAG,GAAG,IAAI,MAAM,CAAC,QAAQ,GAAG,2BAA2B,CAAC;QACxE,CAAC,CAAC,cAAc,GAAG,GAAG,IAAI,MAAM,CAAC,2BAA2B,GAAG,QAAQ,CAAC,CAAA;IAE5E,MAAM,IAAI,GAAG,MAAM,GAAG,kBAAkB,CAAA;IAExC,IAAI,cAAc,GAAG,EAAE,IAAI,IAAI,IAAI,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,wBAAwB,CAChC,wBAAwB,EACxB,gBAAgB,KAAK,cAAc,cAAc,yBAAyB,QAAQ,aAAa;YAC7F,2CAA2C,CAC9C,CAAA;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC,CAAA"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { LimitSwapCancelInputs } from './limitSwapCancelMemo.js';
|
|
2
|
+
export declare const limitSwapCancelBlockers: readonly ["terminal", "cancelAlreadyBroadcast", "missingSignedData", "signedDataDisagreesWithChain", "memoTooLongForSourceChain", "unroutableSourceChain"];
|
|
3
|
+
export type LimitSwapCancelBlocker = (typeof limitSwapCancelBlockers)[number];
|
|
4
|
+
/**
|
|
5
|
+
* Which spelling of an asset a cancel memo may use, or why there isn't one.
|
|
6
|
+
*/
|
|
7
|
+
export type LimitSwapCancelAssetResolution = {
|
|
8
|
+
resolved: string;
|
|
9
|
+
} | {
|
|
10
|
+
problem: 'disagrees';
|
|
11
|
+
} | {
|
|
12
|
+
problem: 'unknown';
|
|
13
|
+
};
|
|
14
|
+
type ResolveLimitSwapCancelAssetInput = {
|
|
15
|
+
/** The PLACEMENT memo's spelling — lossy, usable only when not truncated. */
|
|
16
|
+
stored: string;
|
|
17
|
+
/** The full form captured locally at signing, when it exists. */
|
|
18
|
+
signed?: string;
|
|
19
|
+
/** The queue's own report, after `fuzzyAssetMatch` resolved the placement. */
|
|
20
|
+
observed?: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Resolve which spelling of one of the order's assets a cancel may use.
|
|
24
|
+
*
|
|
25
|
+
* Three sources, in decreasing order of how much they prove:
|
|
26
|
+
*
|
|
27
|
+
* 1. **The queue's own report** — the string THORChain built this order's index
|
|
28
|
+
* entry from. Authoritative by construction, and the only source for an
|
|
29
|
+
* order placed before the full form was recorded locally.
|
|
30
|
+
* 2. **The full form captured at signing** — derived from the coin's own
|
|
31
|
+
* contract, so exact whenever it exists.
|
|
32
|
+
* 3. **The stored placement spelling** — usable ONLY when it carries no
|
|
33
|
+
* truncated identifier, which makes it full by construction. That covers
|
|
34
|
+
* every native leg (`BTC.BTC`, `THOR.RUNE`) and every secured denom.
|
|
35
|
+
*
|
|
36
|
+
* `disagrees` when a local spelling and the chain's own differ: one is wrong
|
|
37
|
+
* and there is no way to tell which. This is the check a real failure needed —
|
|
38
|
+
* the amounts were cross-checked and agreed, the assets were never compared,
|
|
39
|
+
* and the asset was the entire defect.
|
|
40
|
+
*
|
|
41
|
+
* Compared case-insensitively: the sources differ on case by convention (a
|
|
42
|
+
* secured denom is emitted lower-case and reported upper-case, and
|
|
43
|
+
* `common.ParseCoin` upper-cases whatever it is given). Anything beyond case is
|
|
44
|
+
* a real difference.
|
|
45
|
+
*/
|
|
46
|
+
export declare const resolveLimitSwapCancelAsset: ({ stored, signed, observed, }: ResolveLimitSwapCancelAssetInput) => LimitSwapCancelAssetResolution;
|
|
47
|
+
export type LimitSwapCancelCandidate = {
|
|
48
|
+
/** Whether the order has already closed. */
|
|
49
|
+
isTerminal: boolean;
|
|
50
|
+
/** Whether a cancel has already been broadcast against this order. */
|
|
51
|
+
hasPendingCancel?: boolean;
|
|
52
|
+
/** Source asset as the PLACEMENT memo spelled it. */
|
|
53
|
+
sourceAsset: string;
|
|
54
|
+
/** Target asset as the PLACEMENT memo spelled it. */
|
|
55
|
+
targetAsset: string;
|
|
56
|
+
/** Full source spelling captured at signing, if recorded. */
|
|
57
|
+
signedSourceAsset?: string;
|
|
58
|
+
/** Full target spelling captured at signing, if recorded. */
|
|
59
|
+
signedTargetAsset?: string;
|
|
60
|
+
/** Deposited source amount recorded at signing, in 1e8. */
|
|
61
|
+
signedSourceAmount?: bigint;
|
|
62
|
+
/** Trade target recorded at signing, in 1e8. */
|
|
63
|
+
signedTradeTarget?: bigint;
|
|
64
|
+
/** The queue's `coins[0].asset`, once polled. */
|
|
65
|
+
observedSourceAsset?: string;
|
|
66
|
+
/** The queue's `target_asset`, once polled. */
|
|
67
|
+
observedTargetAsset?: string;
|
|
68
|
+
/** The queue's `state.deposit`, once polled. */
|
|
69
|
+
observedDeposit?: bigint;
|
|
70
|
+
/** The queue's `trade_target`, once polled. */
|
|
71
|
+
observedTradeTarget?: bigint;
|
|
72
|
+
};
|
|
73
|
+
export type LimitSwapCancelEligibility = {
|
|
74
|
+
cancellable: LimitSwapCancelInputs;
|
|
75
|
+
} | {
|
|
76
|
+
blocked: LimitSwapCancelBlocker;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Decide whether an order can be cancelled, and if so with which exact amounts.
|
|
80
|
+
*
|
|
81
|
+
* **Fails closed at every unknown.** The failure this guards against is not a
|
|
82
|
+
* crash or an error dialog — it is a cancel that is accepted, costs a fee, and
|
|
83
|
+
* silently matches no order at all. Every branch that cannot prove the values
|
|
84
|
+
* are the ones THORChain holds returns a blocker.
|
|
85
|
+
*
|
|
86
|
+
* The signed-versus-observed cross-check covers assets as well as amounts.
|
|
87
|
+
* Absence is NOT disagreement: an order placed seconds ago has not been polled,
|
|
88
|
+
* and refusing to cancel until the first poll lands would be a worse failure
|
|
89
|
+
* than the one this prevents. But present-and-unparseable blocks exactly as a
|
|
90
|
+
* mismatch does — "not polled yet" and "polled, and the wire carried something
|
|
91
|
+
* we do not model" are different claims, and only the first is safe to proceed
|
|
92
|
+
* through.
|
|
93
|
+
*/
|
|
94
|
+
export declare const getLimitSwapCancelEligibility: (candidate: LimitSwapCancelCandidate) => LimitSwapCancelEligibility;
|
|
95
|
+
export {};
|
|
96
|
+
//# sourceMappingURL=limitSwapCancelEligibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limitSwapCancelEligibility.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/native/limitSwapCancelEligibility.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,qBAAqB,EACtB,MAAM,uBAAuB,CAAA;AAG9B,eAAO,MAAM,uBAAuB,4JA+B1B,CAAA;AAEV,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE7E;;GAEG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,SAAS,CAAA;CAAE,CAAA;AAErH,KAAK,gCAAgC,GAAG;IACtC,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAOD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,2BAA2B,GAAI,+BAIzC,gCAAgC,KAAG,8BAmBrC,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,4CAA4C;IAC5C,UAAU,EAAE,OAAO,CAAA;IACnB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAA;IACnB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAA;IACnB,6DAA6D;IAC7D,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,6DAA6D;IAC7D,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,2DAA2D;IAC3D,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,iDAAiD;IACjD,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,+CAA+C;IAC/C,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,+CAA+C;IAC/C,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IAAE,WAAW,EAAE,qBAAqB,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,sBAAsB,CAAA;CAAE,CAAA;AAErH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,6BAA6B,GAAI,WAAW,wBAAwB,KAAG,0BA4EnF,CAAA"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { buildCancelLimitSwapMemo, doesCancelLimitSwapMemoFit, isAbbreviatedThorchainMemoAsset, } from './limitSwapCancelMemo.js';
|
|
2
|
+
import { getLimitSwapSourceChainKind } from './limitSwapMemo.js';
|
|
3
|
+
export const limitSwapCancelBlockers = [
|
|
4
|
+
/** The order has already closed. Nothing left to cancel. */
|
|
5
|
+
'terminal',
|
|
6
|
+
/**
|
|
7
|
+
* A cancel for this order has already been broadcast and is waiting to be
|
|
8
|
+
* observed. Without this, a user could pay the fee (and on L1 donate the
|
|
9
|
+
* dust) again for an identical memo landing in the identical bucket.
|
|
10
|
+
*/
|
|
11
|
+
'cancelAlreadyBroadcast',
|
|
12
|
+
/**
|
|
13
|
+
* The order predates the fields cancelling needs, or no source can supply an
|
|
14
|
+
* asset's full spelling. Fails closed rather than guessing at the values the
|
|
15
|
+
* matcher keys on.
|
|
16
|
+
*/
|
|
17
|
+
'missingSignedData',
|
|
18
|
+
/**
|
|
19
|
+
* What was recorded at signing and what the queue reports disagree. One of
|
|
20
|
+
* them is wrong and there is no way to tell which, so neither is signed.
|
|
21
|
+
*/
|
|
22
|
+
'signedDataDisagreesWithChain',
|
|
23
|
+
/**
|
|
24
|
+
* The cancel memo does not fit the source chain's per-transaction budget —
|
|
25
|
+
* in practice an ERC20 target from a UTXO source. Nothing in a cancel memo
|
|
26
|
+
* can be shortened, so the order simply refunds at expiry instead.
|
|
27
|
+
*/
|
|
28
|
+
'memoTooLongForSourceChain',
|
|
29
|
+
/**
|
|
30
|
+
* The source asset names a chain THORChain cannot route, so there is no
|
|
31
|
+
* inbound vault to send the cancel to and no byte budget to size it against.
|
|
32
|
+
*/
|
|
33
|
+
'unroutableSourceChain',
|
|
34
|
+
];
|
|
35
|
+
const trimmed = (value) => {
|
|
36
|
+
const text = value?.trim();
|
|
37
|
+
return text ? text : undefined;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Resolve which spelling of one of the order's assets a cancel may use.
|
|
41
|
+
*
|
|
42
|
+
* Three sources, in decreasing order of how much they prove:
|
|
43
|
+
*
|
|
44
|
+
* 1. **The queue's own report** — the string THORChain built this order's index
|
|
45
|
+
* entry from. Authoritative by construction, and the only source for an
|
|
46
|
+
* order placed before the full form was recorded locally.
|
|
47
|
+
* 2. **The full form captured at signing** — derived from the coin's own
|
|
48
|
+
* contract, so exact whenever it exists.
|
|
49
|
+
* 3. **The stored placement spelling** — usable ONLY when it carries no
|
|
50
|
+
* truncated identifier, which makes it full by construction. That covers
|
|
51
|
+
* every native leg (`BTC.BTC`, `THOR.RUNE`) and every secured denom.
|
|
52
|
+
*
|
|
53
|
+
* `disagrees` when a local spelling and the chain's own differ: one is wrong
|
|
54
|
+
* and there is no way to tell which. This is the check a real failure needed —
|
|
55
|
+
* the amounts were cross-checked and agreed, the assets were never compared,
|
|
56
|
+
* and the asset was the entire defect.
|
|
57
|
+
*
|
|
58
|
+
* Compared case-insensitively: the sources differ on case by convention (a
|
|
59
|
+
* secured denom is emitted lower-case and reported upper-case, and
|
|
60
|
+
* `common.ParseCoin` upper-cases whatever it is given). Anything beyond case is
|
|
61
|
+
* a real difference.
|
|
62
|
+
*/
|
|
63
|
+
export const resolveLimitSwapCancelAsset = ({ stored, signed, observed, }) => {
|
|
64
|
+
const storedIfUsable = isAbbreviatedThorchainMemoAsset(stored) ? undefined : trimmed(stored);
|
|
65
|
+
const local = trimmed(signed) ?? storedIfUsable;
|
|
66
|
+
const chain = trimmed(observed);
|
|
67
|
+
if (!chain) {
|
|
68
|
+
return local ? { resolved: local } : { problem: 'unknown' };
|
|
69
|
+
}
|
|
70
|
+
if (!local) {
|
|
71
|
+
// No local spelling to check against — the legacy token case, rescued by
|
|
72
|
+
// the only source still holding the full contract.
|
|
73
|
+
return { resolved: chain };
|
|
74
|
+
}
|
|
75
|
+
if (local.toLowerCase() !== chain.toLowerCase()) {
|
|
76
|
+
return { problem: 'disagrees' };
|
|
77
|
+
}
|
|
78
|
+
// Proven equal bar case, so the local spelling is kept: it is the exact byte
|
|
79
|
+
// form this SDK derived.
|
|
80
|
+
return { resolved: local };
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Decide whether an order can be cancelled, and if so with which exact amounts.
|
|
84
|
+
*
|
|
85
|
+
* **Fails closed at every unknown.** The failure this guards against is not a
|
|
86
|
+
* crash or an error dialog — it is a cancel that is accepted, costs a fee, and
|
|
87
|
+
* silently matches no order at all. Every branch that cannot prove the values
|
|
88
|
+
* are the ones THORChain holds returns a blocker.
|
|
89
|
+
*
|
|
90
|
+
* The signed-versus-observed cross-check covers assets as well as amounts.
|
|
91
|
+
* Absence is NOT disagreement: an order placed seconds ago has not been polled,
|
|
92
|
+
* and refusing to cancel until the first poll lands would be a worse failure
|
|
93
|
+
* than the one this prevents. But present-and-unparseable blocks exactly as a
|
|
94
|
+
* mismatch does — "not polled yet" and "polled, and the wire carried something
|
|
95
|
+
* we do not model" are different claims, and only the first is safe to proceed
|
|
96
|
+
* through.
|
|
97
|
+
*/
|
|
98
|
+
export const getLimitSwapCancelEligibility = (candidate) => {
|
|
99
|
+
if (candidate.isTerminal) {
|
|
100
|
+
return { blocked: 'terminal' };
|
|
101
|
+
}
|
|
102
|
+
if (candidate.hasPendingCancel) {
|
|
103
|
+
return { blocked: 'cancelAlreadyBroadcast' };
|
|
104
|
+
}
|
|
105
|
+
const { signedSourceAmount, signedTradeTarget } = candidate;
|
|
106
|
+
if (signedSourceAmount === undefined ||
|
|
107
|
+
signedTradeTarget === undefined ||
|
|
108
|
+
signedSourceAmount <= 0n ||
|
|
109
|
+
signedTradeTarget <= 0n) {
|
|
110
|
+
return { blocked: 'missingSignedData' };
|
|
111
|
+
}
|
|
112
|
+
// `state.deposit` IS the swap's `Tx.Coins[0].Amount` and `trade_target` IS
|
|
113
|
+
// `msg.TradeTarget` — the exact pair the matcher's ratio is computed from.
|
|
114
|
+
if (candidate.observedDeposit !== undefined && candidate.observedDeposit !== signedSourceAmount) {
|
|
115
|
+
return { blocked: 'signedDataDisagreesWithChain' };
|
|
116
|
+
}
|
|
117
|
+
if (candidate.observedTradeTarget !== undefined && candidate.observedTradeTarget !== signedTradeTarget) {
|
|
118
|
+
return { blocked: 'signedDataDisagreesWithChain' };
|
|
119
|
+
}
|
|
120
|
+
const source = resolveLimitSwapCancelAsset({
|
|
121
|
+
stored: candidate.sourceAsset,
|
|
122
|
+
signed: candidate.signedSourceAsset,
|
|
123
|
+
observed: candidate.observedSourceAsset,
|
|
124
|
+
});
|
|
125
|
+
const target = resolveLimitSwapCancelAsset({
|
|
126
|
+
stored: candidate.targetAsset,
|
|
127
|
+
signed: candidate.signedTargetAsset,
|
|
128
|
+
observed: candidate.observedTargetAsset,
|
|
129
|
+
});
|
|
130
|
+
if (!('resolved' in source) || !('resolved' in target)) {
|
|
131
|
+
const disagrees = ('problem' in source && source.problem === 'disagrees') || ('problem' in target && target.problem === 'disagrees');
|
|
132
|
+
return { blocked: disagrees ? 'signedDataDisagreesWithChain' : 'missingSignedData' };
|
|
133
|
+
}
|
|
134
|
+
const inputs = {
|
|
135
|
+
sourceAsset: source.resolved,
|
|
136
|
+
sourceAmount: signedSourceAmount,
|
|
137
|
+
targetAsset: target.resolved,
|
|
138
|
+
tradeTarget: signedTradeTarget,
|
|
139
|
+
};
|
|
140
|
+
// The memo must be buildable AND fit the chain it will be sent from. Checked
|
|
141
|
+
// here rather than at signing so the action is never offered for an order
|
|
142
|
+
// that cannot actually be cancelled.
|
|
143
|
+
let memo;
|
|
144
|
+
try {
|
|
145
|
+
memo = buildCancelLimitSwapMemo(inputs);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return { blocked: 'missingSignedData' };
|
|
149
|
+
}
|
|
150
|
+
// Resolved in its own guarded step: the memo builder does not check
|
|
151
|
+
// routability, so an unrecognised prefix reaches this call and throws —
|
|
152
|
+
// escaping a function whose whole contract is to answer with a blocker.
|
|
153
|
+
let sourceChainKind;
|
|
154
|
+
try {
|
|
155
|
+
sourceChainKind = getLimitSwapSourceChainKind(inputs.sourceAsset);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return { blocked: 'unroutableSourceChain' };
|
|
159
|
+
}
|
|
160
|
+
if (!doesCancelLimitSwapMemoFit(memo, sourceChainKind)) {
|
|
161
|
+
return { blocked: 'memoTooLongForSourceChain' };
|
|
162
|
+
}
|
|
163
|
+
return { cancellable: inputs };
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=limitSwapCancelEligibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limitSwapCancelEligibility.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/native/limitSwapCancelEligibility.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,+BAA+B,GAEhC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,2BAA2B,EAA4B,MAAM,iBAAiB,CAAA;AAEvF,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,4DAA4D;IAC5D,UAAU;IACV;;;;OAIG;IACH,wBAAwB;IACxB;;;;OAIG;IACH,mBAAmB;IACnB;;;OAGG;IACH,8BAA8B;IAC9B;;;;OAIG;IACH,2BAA2B;IAC3B;;;OAGG;IACH,uBAAuB;CACf,CAAA;AAkBV,MAAM,OAAO,GAAG,CAAC,KAAyB,EAAsB,EAAE;IAChE,MAAM,IAAI,GAAG,KAAK,EAAE,IAAI,EAAE,CAAA;IAC1B,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;AAChC,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,EAC1C,MAAM,EACN,MAAM,EACN,QAAQ,GACyB,EAAkC,EAAE;IACrE,MAAM,cAAc,GAAG,+BAA+B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAC5F,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,cAAc,CAAA;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAE/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAA;IAC7D,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,yEAAyE;QACzE,mDAAmD;QACnD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;IAC5B,CAAC;IACD,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;QAChD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,CAAA;IACjC,CAAC;IACD,6EAA6E;IAC7E,yBAAyB;IACzB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AAC5B,CAAC,CAAA;AA+BD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,SAAmC,EAA8B,EAAE;IAC/G,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAA;IAChC,CAAC;IACD,IAAI,SAAS,CAAC,gBAAgB,EAAE,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAA;IAC9C,CAAC;IAED,MAAM,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAA;IAC3D,IACE,kBAAkB,KAAK,SAAS;QAChC,iBAAiB,KAAK,SAAS;QAC/B,kBAAkB,IAAI,EAAE;QACxB,iBAAiB,IAAI,EAAE,EACvB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAA;IACzC,CAAC;IAED,2EAA2E;IAC3E,2EAA2E;IAC3E,IAAI,SAAS,CAAC,eAAe,KAAK,SAAS,IAAI,SAAS,CAAC,eAAe,KAAK,kBAAkB,EAAE,CAAC;QAChG,OAAO,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAA;IACpD,CAAC;IACD,IAAI,SAAS,CAAC,mBAAmB,KAAK,SAAS,IAAI,SAAS,CAAC,mBAAmB,KAAK,iBAAiB,EAAE,CAAC;QACvG,OAAO,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAA;IACpD,CAAC;IAED,MAAM,MAAM,GAAG,2BAA2B,CAAC;QACzC,MAAM,EAAE,SAAS,CAAC,WAAW;QAC7B,MAAM,EAAE,SAAS,CAAC,iBAAiB;QACnC,QAAQ,EAAE,SAAS,CAAC,mBAAmB;KACxC,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,2BAA2B,CAAC;QACzC,MAAM,EAAE,SAAS,CAAC,WAAW;QAC7B,MAAM,EAAE,SAAS,CAAC,iBAAiB;QACnC,QAAQ,EAAE,SAAS,CAAC,mBAAmB;KACxC,CAAC,CAAA;IAEF,IAAI,CAAC,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,IAAI,MAAM,CAAC,EAAE,CAAC;QACvD,MAAM,SAAS,GACb,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,CAAC,OAAO,KAAK,WAAW,CAAC,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,CAAC,OAAO,KAAK,WAAW,CAAC,CAAA;QACpH,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAA;IACtF,CAAC;IAED,MAAM,MAAM,GAA0B;QACpC,WAAW,EAAE,MAAM,CAAC,QAAQ;QAC5B,YAAY,EAAE,kBAAkB;QAChC,WAAW,EAAE,MAAM,CAAC,QAAQ;QAC5B,WAAW,EAAE,iBAAiB;KAC/B,CAAA;IAED,6EAA6E;IAC7E,0EAA0E;IAC1E,qCAAqC;IACrC,IAAI,IAAY,CAAA;IAChB,IAAI,CAAC;QACH,IAAI,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAA;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAA;IACzC,CAAC;IAED,oEAAoE;IACpE,wEAAwE;IACxE,wEAAwE;IACxE,IAAI,eAAyC,CAAA;IAC7C,IAAI,CAAC;QACH,eAAe,GAAG,2BAA2B,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAA;IAC7C,CAAC;IAED,IAAI,CAAC,0BAA0B,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE,CAAC;QACvD,OAAO,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAA;IACjD,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAA;AAChC,CAAC,CAAA"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { LimitSwapSourceChainKind } from './limitSwapMemo.js';
|
|
2
|
+
/**
|
|
3
|
+
* THORChain's modify-limit-swap prefix. Distinct from `limitSwapMemoPrefix`
|
|
4
|
+
* (`=<:`), which PLACES an order — `m=<:` modifies one that is already resting.
|
|
5
|
+
*/
|
|
6
|
+
export declare const modifyLimitSwapMemoPrefix = "m=<:";
|
|
7
|
+
/**
|
|
8
|
+
* Whether `memo` MODIFIES a resting order — which includes, but is not limited
|
|
9
|
+
* to, cancelling it.
|
|
10
|
+
*
|
|
11
|
+
* Named for what it matches. A cancel is the special case where the final field
|
|
12
|
+
* is zero; a non-zero value re-targets. Only the cancel form is built here, so
|
|
13
|
+
* today the two coincide — but a predicate that says "cancel" while matching
|
|
14
|
+
* any modification is the kind of small lie that outlives the assumption that
|
|
15
|
+
* made it true.
|
|
16
|
+
*/
|
|
17
|
+
export declare const isModifyLimitSwapMemo: (memo: string | undefined | null) => boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Whether `memo` CANCELS a resting order, rather than merely modifying one.
|
|
20
|
+
*
|
|
21
|
+
* The final field is compared NUMERICALLY, the way THORNode's `getUint` reads
|
|
22
|
+
* it: `"00"` is zero there, and a string comparison would call that a retarget.
|
|
23
|
+
* Digits only, so a sign cannot smuggle `"-0"` past an unsigned field.
|
|
24
|
+
*/
|
|
25
|
+
export declare const isCancelLimitSwapMemo: (memo: string | undefined | null) => boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Everything the cancel memo needs, reduced to the exact integers THORChain
|
|
28
|
+
* itself holds. Amounts are bigint so a caller cannot pass an unparsed or
|
|
29
|
+
* negative value.
|
|
30
|
+
*/
|
|
31
|
+
export type LimitSwapCancelInputs = {
|
|
32
|
+
/**
|
|
33
|
+
* THORChain memo form of the order's SOURCE asset.
|
|
34
|
+
*
|
|
35
|
+
* Must carry the token's FULL contract (`ETH.USDC-0XA0B86991…`), never the
|
|
36
|
+
* placement memo's 6-character abbreviation — see `buildCancelLimitSwapMemo`.
|
|
37
|
+
*
|
|
38
|
+
* Must be the asset's SECURED denom (`eth-usdc-0xa0b…`) when the source is a
|
|
39
|
+
* secured asset, never its layer-1 form. `MsgModifyLimitSwap.ValidateBasic`
|
|
40
|
+
* enforces `From.IsChain(Source.Asset.GetChain())`, and `GetChain()` returns
|
|
41
|
+
* THORChain only for synth, trade and secured assets. The layer-1 spelling
|
|
42
|
+
* makes it report the L1 chain, and a cancel sent from a THOR address is then
|
|
43
|
+
* rejected outright at validation.
|
|
44
|
+
*/
|
|
45
|
+
sourceAsset: string;
|
|
46
|
+
/** The order's deposited source amount, in THORChain's 1e8 fixed point. */
|
|
47
|
+
sourceAmount: bigint;
|
|
48
|
+
/** THORChain memo form of the TARGET asset, under the same full-spelling rule. */
|
|
49
|
+
targetAsset: string;
|
|
50
|
+
/** The order's ORIGINAL trade target (the placement memo's LIM), in 1e8. */
|
|
51
|
+
tradeTarget: bigint;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Whether a memo asset carries a TRUNCATED token identifier —
|
|
55
|
+
* `ETH.USDC-06EB48` rather than `ETH.USDC-0XA0B86991…`.
|
|
56
|
+
*
|
|
57
|
+
* The chain prefix has to be stripped first, and cannot be assumed to end at a
|
|
58
|
+
* `.`: a SECURED asset spells the whole thing with `-`, so a secured native
|
|
59
|
+
* denom is `btc-btc` and a secured token is `eth-usdc-0xa0b…`. Reading the tail
|
|
60
|
+
* after the last `-` would call the first of those truncated and make every
|
|
61
|
+
* secured-native order uncancellable.
|
|
62
|
+
*
|
|
63
|
+
* So: drop everything up to the first separator — that is the chain — and look
|
|
64
|
+
* at the SYMBOL that follows. A symbol is `TICKER` or `TICKER-<identifier>`,
|
|
65
|
+
* and only the second form can be truncated. `BTC.BTC`, `THOR.RUNE` and
|
|
66
|
+
* `btc-btc` carry no identifier at all and are full by construction.
|
|
67
|
+
*/
|
|
68
|
+
export declare const isAbbreviatedThorchainMemoAsset: (asset: string) => boolean;
|
|
69
|
+
export declare const limitSwapCancelMemoErrors: readonly ["emptyAsset", "nonPositiveAmount", "abbreviatedAsset"];
|
|
70
|
+
export type LimitSwapCancelMemoError = (typeof limitSwapCancelMemoErrors)[number];
|
|
71
|
+
export declare class LimitSwapCancelMemoBuildError extends Error {
|
|
72
|
+
readonly reason: LimitSwapCancelMemoError;
|
|
73
|
+
constructor(reason: LimitSwapCancelMemoError, message: string);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Both amounts must be positive, for every consumer of these inputs.
|
|
77
|
+
*
|
|
78
|
+
* Shared because two modules depend on it for different reasons: the memo would
|
|
79
|
+
* encode a coin THORNode cannot parse, and the bucket key divides by the trade
|
|
80
|
+
* target — where a zero would raise `RangeError` rather than a domain error a
|
|
81
|
+
* caller can branch on.
|
|
82
|
+
*/
|
|
83
|
+
export declare const assertPositiveLimitSwapCancelAmounts: ({ sourceAmount, tradeTarget, }: Pick<LimitSwapCancelInputs, "sourceAmount" | "tradeTarget">) => void;
|
|
84
|
+
/**
|
|
85
|
+
* Build the `m=<` memo that cancels a resting limit order.
|
|
86
|
+
*
|
|
87
|
+
* m=<:<SRC_AMOUNT><SRC_ASSET>:<TRADE_TARGET><TGT_ASSET>:0
|
|
88
|
+
*
|
|
89
|
+
* Both coins are `<amount><ASSET>` with NO space — THORNode's `getCoin` scans
|
|
90
|
+
* leading digits and splices the space back in before parsing.
|
|
91
|
+
*
|
|
92
|
+
* Three properties, each of which causes a SILENT no-op if broken — the cancel
|
|
93
|
+
* is accepted, costs a fee, matches nothing, and looks exactly like success:
|
|
94
|
+
*
|
|
95
|
+
* - **Assets are spelled in FULL.** `processOneTxIn` runs every other inbound
|
|
96
|
+
* memo through `fuzzyAssetMatch`, which is what lets a placement say
|
|
97
|
+
* `ETH.USDC-06EB48` and still be indexed under the full contract.
|
|
98
|
+
* `ModifyLimitSwapMemo` is the exception: its asset string builds the lookup
|
|
99
|
+
* key verbatim, so an abbreviation addresses a bucket that by construction
|
|
100
|
+
* holds nothing. Enforced here, not merely documented.
|
|
101
|
+
* - **Amounts are plain decimal integers.** The placement memo's LIM goes
|
|
102
|
+
* through `getUintWithScientificNotation` and understands `544e6`; these
|
|
103
|
+
* coins go through `cosmos.ParseCoins`, which does not.
|
|
104
|
+
* - **Both amounts are exact.** THORNode does not compare them directly — they
|
|
105
|
+
* feed the ratio its index key is built from (see
|
|
106
|
+
* `getThorchainLimitOrderBucketKey`), and one unit of drift lands in a
|
|
107
|
+
* different bucket.
|
|
108
|
+
*/
|
|
109
|
+
export declare const buildCancelLimitSwapMemo: (inputs: LimitSwapCancelInputs) => string;
|
|
110
|
+
/**
|
|
111
|
+
* Whether a cancel memo fits the per-transaction budget of the chain it will be
|
|
112
|
+
* sent from.
|
|
113
|
+
*
|
|
114
|
+
* In practice this rules out an ERC20 target from a UTXO source: two
|
|
115
|
+
* full-contract assets plus two exact amounts overflow the 80-byte OP_RETURN
|
|
116
|
+
* cap, and NOTHING in a cancel memo can be shortened — the amounts define the
|
|
117
|
+
* bucket, short codes are rejected by `cosmos.ParseCoins`, and this memo type
|
|
118
|
+
* skips `fuzzyAssetMatch`. Such an order still refunds automatically at expiry.
|
|
119
|
+
*/
|
|
120
|
+
export declare const doesCancelLimitSwapMemoFit: (memo: string, sourceChainKind: LimitSwapSourceChainKind) => boolean;
|
|
121
|
+
/** Convenience: the byte-cap check keyed off the source asset's memo notation. */
|
|
122
|
+
export declare const doesCancelLimitSwapMemoFitSourceAsset: (memo: string, sourceAsset: string) => boolean;
|
|
123
|
+
//# sourceMappingURL=limitSwapCancelMemo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limitSwapCancelMemo.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/native/limitSwapCancelMemo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuD,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AAE/G;;;GAGG;AACH,eAAO,MAAM,yBAAyB,SAAS,CAAA;AAS/C;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GAAI,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,KAAG,OACzB,CAAA;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAAI,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,KAAG,OAUvE,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;;;;;;;OAYG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAA;IACpB,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAA;IACnB,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAgBD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,+BAA+B,GAAI,OAAO,MAAM,KAAG,OAQ/D,CAAA;AAED,eAAO,MAAM,yBAAyB,kEAAmE,CAAA;AAEzG,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEjF,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAA;gBAE7B,MAAM,EAAE,wBAAwB,EAAE,OAAO,EAAE,MAAM;CAK9D;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oCAAoC,GAAI,gCAGlD,IAAI,CAAC,qBAAqB,EAAE,cAAc,GAAG,aAAa,CAAC,KAAG,IAOhE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,wBAAwB,GAAI,QAAQ,qBAAqB,KAAG,MAwBxE,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,EAAE,iBAAiB,wBAAwB,KAAG,OACnB,CAAA;AAElF,kFAAkF;AAClF,eAAO,MAAM,qCAAqC,GAAI,MAAM,MAAM,EAAE,aAAa,MAAM,KAAG,OACd,CAAA"}
|