@vultisig/core-mpc 1.12.1 → 1.14.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +165 -0
  2. package/dist/chains/cosmos/qbtc/QBTCHelper.js +4 -3
  3. package/dist/chains/cosmos/qbtc/QBTCHelper.js.map +1 -1
  4. package/dist/chains/cosmos/qbtc/QBTCTx.js +1 -1
  5. package/dist/chains/cosmos/qbtc/QBTCTx.js.map +1 -1
  6. package/dist/keysign/chainSpecific/resolvers/cosmos/index.d.ts.map +1 -1
  7. package/dist/keysign/chainSpecific/resolvers/cosmos/index.js +71 -10
  8. package/dist/keysign/chainSpecific/resolvers/cosmos/index.js.map +1 -1
  9. package/dist/keysign/chainSpecific/resolvers/sui/index.d.ts.map +1 -1
  10. package/dist/keysign/chainSpecific/resolvers/sui/index.js +62 -64
  11. package/dist/keysign/chainSpecific/resolvers/sui/index.js.map +1 -1
  12. package/dist/keysign/chainSpecific/resolvers/sui/refine.d.ts.map +1 -1
  13. package/dist/keysign/chainSpecific/resolvers/sui/refine.js +14 -4
  14. package/dist/keysign/chainSpecific/resolvers/sui/refine.js.map +1 -1
  15. package/dist/keysign/chainSpecific/resolvers/tron/energyPrice.d.ts +4 -3
  16. package/dist/keysign/chainSpecific/resolvers/tron/energyPrice.d.ts.map +1 -1
  17. package/dist/keysign/chainSpecific/resolvers/tron/energyPrice.js +11 -5
  18. package/dist/keysign/chainSpecific/resolvers/tron/energyPrice.js.map +1 -1
  19. package/dist/keysign/chainSpecific/resolvers/tron/fee.d.ts +11 -0
  20. package/dist/keysign/chainSpecific/resolvers/tron/fee.d.ts.map +1 -1
  21. package/dist/keysign/chainSpecific/resolvers/tron/fee.js +43 -19
  22. package/dist/keysign/chainSpecific/resolvers/tron/fee.js.map +1 -1
  23. package/dist/keysign/fee/resolvers/cosmos.d.ts +5 -3
  24. package/dist/keysign/fee/resolvers/cosmos.d.ts.map +1 -1
  25. package/dist/keysign/fee/resolvers/cosmos.js +8 -21
  26. package/dist/keysign/fee/resolvers/cosmos.js.map +1 -1
  27. package/dist/keysign/fee/resolvers/tron.d.ts.map +1 -1
  28. package/dist/keysign/fee/resolvers/tron.js +11 -2
  29. package/dist/keysign/fee/resolvers/tron.js.map +1 -1
  30. package/dist/keysign/signingInputs/resolvers/cosmos/index.d.ts.map +1 -1
  31. package/dist/keysign/signingInputs/resolvers/cosmos/index.js +30 -17
  32. package/dist/keysign/signingInputs/resolvers/cosmos/index.js.map +1 -1
  33. package/dist/keysign/swap/buildLimitSwapKeysignPayload.d.ts +86 -0
  34. package/dist/keysign/swap/buildLimitSwapKeysignPayload.d.ts.map +1 -0
  35. package/dist/keysign/swap/buildLimitSwapKeysignPayload.js +178 -0
  36. package/dist/keysign/swap/buildLimitSwapKeysignPayload.js.map +1 -0
  37. package/dist/keysign/swap/getKeysignLimitSwapOrder.d.ts +41 -0
  38. package/dist/keysign/swap/getKeysignLimitSwapOrder.d.ts.map +1 -0
  39. package/dist/keysign/swap/getKeysignLimitSwapOrder.js +50 -0
  40. package/dist/keysign/swap/getKeysignLimitSwapOrder.js.map +1 -0
  41. package/package.json +14 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildLimitSwapKeysignPayload.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/mpc/keysign/swap/buildLimitSwapKeysignPayload.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAA;AAYnE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAA;AAKzE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAiB7C,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,EAAE,WAAW,CAAA;IACrB,MAAM,EAAE,WAAW,CAAA;IACnB,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAA;IACd,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,SAAS,CAAA;IACxB,WAAW,EAAE,SAAS,CAAA;IACtB,OAAO,EAAE,cAAc,CAAA;IACvB,UAAU,EAAE,UAAU,CAAA;IACtB;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,0FAA0F;IAC1F,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,eAAO,MAAM,4BAA4B,GAAU,oIAahD,iCAAiC,yFA8HnC,CAAA"}
@@ -0,0 +1,178 @@
1
+ import { Buffer } from 'buffer';
2
+ import { create } from '@bufbuild/protobuf';
3
+ import { fromChainAmountDisplay } from '@vultisig/core-chain/amount/fromChainAmountExact';
4
+ import { Chain } from '@vultisig/core-chain/Chain';
5
+ import { isChainOfKind } from '@vultisig/core-chain/ChainKind';
6
+ import { getThorchainInboundAddress } from '@vultisig/core-chain/chains/cosmos/thor/getThorchainInboundAddress';
7
+ import { getErc20Allowance } from '@vultisig/core-chain/chains/evm/erc20/getErc20Allowance';
8
+ import { chainFeeCoin } from '@vultisig/core-chain/coin/chainFeeCoin';
9
+ import { areEqualCoins } from '@vultisig/core-chain/coin/Coin';
10
+ import { isFeeCoin } from '@vultisig/core-chain/coin/utils/isFeeCoin';
11
+ import { getAdvancedSwapQueueEnabled } from '@vultisig/core-chain/swap/native/limitSwapAvailability';
12
+ import { findLimitSwapInbound, isLimitSwapDestinationHalted, shouldBlockRuneDeposit, } from '@vultisig/core-chain/swap/native/limitSwapInbound';
13
+ import { parseLimitSwapMemo } from '@vultisig/core-chain/swap/native/limitSwapMemo';
14
+ import { getNativeSwapDecimals } from '@vultisig/core-chain/swap/native/utils/getNativeSwapDecimals';
15
+ import { getChainSpecific } from '../chainSpecific/index.js';
16
+ import { refineKeysignUtxo } from '../refine/utxo.js';
17
+ import { getKeysignUtxoInfo } from '../utxo/getKeysignUtxoInfo.js';
18
+ import { toCommCoin } from '../../types/utils/commCoin.js';
19
+ import { Erc20ApprovePayloadSchema } from '../../types/vultisig/keysign/v1/erc20_approve_payload_pb.js';
20
+ import { KeysignPayloadSchema } from '../../types/vultisig/keysign/v1/keysign_message_pb.js';
21
+ import { THORChainSwapPayloadSchema } from '../../types/vultisig/keysign/v1/thorchain_swap_payload_pb.js';
22
+ /**
23
+ * On-chain deadline for the router's `depositWithExpiry` call.
24
+ *
25
+ * This bounds when the *deposit transaction* may execute — a stale, long-
26
+ * unconfirmed tx cannot land later. It is NOT the resting order's lifetime: that
27
+ * is the memo's interval, up to 3 days, evaluated per block by THORChain. Once
28
+ * THORChain observes the deposit (a block or two, far inside this window) the
29
+ * order rests for its full memo TTL regardless of this value.
30
+ */
31
+ const routerExpiryMs = 15 * 60 * 1000;
32
+ /**
33
+ * Build the `KeysignPayload` for a THORChain limit order.
34
+ *
35
+ * The limit-ness always lives in the memo (`=<` vs the market `=>`); how that
36
+ * memo reaches the chain depends on the source asset:
37
+ *
38
+ * - **Native RUNE** — `MsgDeposit` on THORChain itself. No inbound vault and no
39
+ * real destination, so `toAddress` carries the signer's own address as a
40
+ * placeholder (the Cosmos signer keys off `isDeposit`, not `toAddress`).
41
+ * - **Native gas asset** (BTC/ETH/AVAX/…) — a plain transfer to the Asgard
42
+ * inbound vault with the memo in tx `data` / `OP_RETURN`. No swap payload.
43
+ * - **ERC20** — the router's `depositWithExpiry(vault, asset, amount, memo,
44
+ * expiry)` call, which needs `approve(router, amount)` first. Both ride one
45
+ * ceremony, mirroring the market ERC20 THORChain swap. A token source signed
46
+ * *without* a swap payload would fall through to a plain ERC20 transfer,
47
+ * dropping the memo and stranding the tokens on the router — so it must carry
48
+ * one.
49
+ *
50
+ * The swap payload is deliberately NOT attached to the first two branches, even
51
+ * though it would give co-signers the market path's swap review for free
52
+ * (sdk#1611). It is not display metadata: every signing-input resolver re-routes
53
+ * on its presence — UTXO takes both amount and destination from it, EVM and Tron
54
+ * take the destination from `vaultAddress`, and the Cosmos resolver drops the
55
+ * tx-body memo (`txMemo: swapPayload ? '' : memo`). Attaching one would change
56
+ * signed bytes on a working path to improve a display, and for RUNE it would
57
+ * additionally make `assertNativeSwapReadyForBroadcast` resolve a `THOR` inbound
58
+ * row that THORChain's own inbound list does not contain, failing the broadcast
59
+ * guard outright. Joining devices get the order terms from
60
+ * `getKeysignLimitSwapOrder` instead, which reads the memo that every branch
61
+ * already carries — and which, being the string THORChain executes, cannot
62
+ * disagree with what is signed.
63
+ *
64
+ * Fund-safety gates, all fail-closed:
65
+ * - The `EnableAdvSwapQueue` mimir is re-checked here, at sign time. Placement
66
+ * was already gated on it, but it can flip while the user sits on Verify, and
67
+ * a `=<` order on a network with the queue disabled can execute as an
68
+ * unprotected market swap.
69
+ * - The memo must actually be a limit memo.
70
+ * - RUNE deposits are blocked on THORChain's global trading pause (they bypass
71
+ * the per-chain inbound halt filter entirely), including when the inbound list
72
+ * is unverifiable — and on a halted destination chain: with no swap payload
73
+ * attached, the broadcast guard's destination-leg re-check never runs for
74
+ * them, so sign time is their only destination gate.
75
+ * - External sources must resolve a live, non-halted, non-paused inbound row,
76
+ * and the destination is taken from that same live view rather than a cache.
77
+ *
78
+ * Gas: unlike iOS, no EVM gas-limit override is applied. iOS pins a native-EVM
79
+ * limit deposit to 120000 to match its own market path; here both paths put the
80
+ * memo on `keysignPayload.memo` and neither sets a general swap payload, so both
81
+ * already floor at `deriveEvmGasLimit`'s 600000 data-tx limit. Forcing 120000
82
+ * would make the limit path diverge from the market path and risk under-gassing.
83
+ */
84
+ export const buildLimitSwapKeysignPayload = async ({ fromCoin, toCoin, amount, memo, vaultId, localPartyId, fromPublicKey, toPublicKey, libType, walletCore, expectedToAmount, now = Date.now(), }) => {
85
+ const order = parseLimitSwapMemo(memo);
86
+ if (expectedToAmount !== undefined && expectedToAmount !== order.limit) {
87
+ throw new Error(`buildLimitSwapKeysignPayload: expectedToAmount ${expectedToAmount} disagrees with the memo's LIM ${order.limit}. ` +
88
+ "It must be the LIM in THORChain's 1e8 fixed point, not rescaled to the target coin's decimals.");
89
+ }
90
+ if (amount <= 0n) {
91
+ throw new Error('buildLimitSwapKeysignPayload: amount must be greater than 0');
92
+ }
93
+ if (!(await getAdvancedSwapQueueEnabled())) {
94
+ throw new Error("THORChain's advanced swap queue is disabled; a limit order placed now could execute as an unprotected market swap");
95
+ }
96
+ const fromCoinHexPublicKey = Buffer.from(fromPublicKey.data()).toString('hex');
97
+ const toCoinHexPublicKey = Buffer.from(toPublicKey.data()).toString('hex');
98
+ const isRuneDeposit = areEqualCoins(fromCoin, chainFeeCoin[Chain.THORChain]);
99
+ const inbounds = await getThorchainInboundAddress();
100
+ const { toAddress, swapPayload, approveSpender } = (() => {
101
+ if (isRuneDeposit) {
102
+ if (shouldBlockRuneDeposit(inbounds)) {
103
+ throw new Error('THORChain has globally paused trading (or its inbound list is unverifiable); refusing to sign a RUNE limit-order deposit');
104
+ }
105
+ if (isLimitSwapDestinationHalted({ inbounds, chain: toCoin.chain })) {
106
+ throw new Error(`THORChain has halted ${toCoin.chain} trading; refusing to sign a RUNE limit-order deposit whose outbound could not leave`);
107
+ }
108
+ return { toAddress: fromCoin.address };
109
+ }
110
+ const inbound = findLimitSwapInbound({ inbounds, chain: fromCoin.chain });
111
+ if (isFeeCoin(fromCoin)) {
112
+ return { toAddress: inbound.address };
113
+ }
114
+ const { router } = inbound;
115
+ if (!router) {
116
+ throw new Error(`buildLimitSwapKeysignPayload: THORChain's ${inbound.chain} inbound has no router contract, so a token deposit cannot be built`);
117
+ }
118
+ return {
119
+ toAddress: router,
120
+ approveSpender: router,
121
+ swapPayload: create(THORChainSwapPayloadSchema, {
122
+ fromAddress: fromCoin.address,
123
+ fromCoin: toCommCoin({ ...fromCoin, hexPublicKey: fromCoinHexPublicKey }),
124
+ toCoin: toCommCoin({ ...toCoin, hexPublicKey: toCoinHexPublicKey }),
125
+ vaultAddress: inbound.address,
126
+ routerAddress: router,
127
+ fromAmount: amount.toString(),
128
+ // Display-only, for the co-signer's "you receive" row. The order's real
129
+ // floor is the LIM inside the memo; these fields are never read here.
130
+ toAmountDecimal: fromChainAmountDisplay(order.limit, getNativeSwapDecimals(toCoin)),
131
+ toAmountLimit: '0',
132
+ streamingInterval: '0',
133
+ streamingQuantity: '0',
134
+ expirationTime: BigInt(Math.floor((now + routerExpiryMs) / 1000)),
135
+ isAffiliate: true,
136
+ }),
137
+ };
138
+ })();
139
+ let keysignPayload = create(KeysignPayloadSchema, {
140
+ coin: toCommCoin({ ...fromCoin, hexPublicKey: fromCoinHexPublicKey }),
141
+ toAmount: amount.toString(),
142
+ vaultLocalPartyId: localPartyId,
143
+ vaultPublicKeyEcdsa: vaultId,
144
+ libType,
145
+ toAddress,
146
+ memo,
147
+ utxoInfo: await getKeysignUtxoInfo(fromCoin),
148
+ ...(swapPayload ? { swapPayload: { case: 'thorchainSwapPayload', value: swapPayload } } : {}),
149
+ });
150
+ keysignPayload.blockchainSpecific = await getChainSpecific({
151
+ keysignPayload,
152
+ walletCore,
153
+ isDeposit: isRuneDeposit,
154
+ });
155
+ if (approveSpender && isChainOfKind(fromCoin.chain, 'evm') && fromCoin.id) {
156
+ const allowance = await getErc20Allowance({
157
+ chain: fromCoin.chain,
158
+ id: fromCoin.id,
159
+ address: fromCoin.address,
160
+ spender: approveSpender,
161
+ });
162
+ if (allowance < amount) {
163
+ keysignPayload.erc20ApprovePayload = create(Erc20ApprovePayloadSchema, {
164
+ amount: amount.toString(),
165
+ spender: approveSpender,
166
+ });
167
+ }
168
+ }
169
+ if (isChainOfKind(fromCoin.chain, 'utxo')) {
170
+ keysignPayload = await refineKeysignUtxo({
171
+ keysignPayload,
172
+ walletCore,
173
+ publicKey: fromPublicKey,
174
+ });
175
+ }
176
+ return keysignPayload;
177
+ };
178
+ //# sourceMappingURL=buildLimitSwapKeysignPayload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildLimitSwapKeysignPayload.js","sourceRoot":"","sources":["../../../../../../packages/core/mpc/keysign/swap/buildLimitSwapKeysignPayload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { Chain } from '@vultisig/core-chain/Chain';
2
+ import { LimitSwapExpiryHours, ParsedLimitSwapMemo } from '@vultisig/core-chain/swap/native/limitSwapMemo';
3
+ import { KeysignPayload } from '../../types/vultisig/keysign/v1/keysign_message_pb.js';
4
+ export type KeysignLimitSwapOrder = ParsedLimitSwapMemo & {
5
+ /** The buy chain, when the target asset's prefix is one this SDK can route. */
6
+ targetChain?: Chain;
7
+ /**
8
+ * Guaranteed-minimum received, as a decimal string in the target asset's
9
+ * display units. Formatted from the LIM with THORChain's 8 decimals, matching
10
+ * how `toAmountDecimal` is formatted for market swaps.
11
+ */
12
+ minimumReceivedDecimal: string;
13
+ /** The order's resting lifetime, when the interval maps to one this SDK builds. */
14
+ expiryHours?: LimitSwapExpiryHours;
15
+ };
16
+ /**
17
+ * Decode the limit order a keysign payload is about to place, for review.
18
+ *
19
+ * Returns `undefined` for any payload that is not a limit order, so a caller can
20
+ * branch on it directly.
21
+ *
22
+ * **This is how a *joining* device reviews a limit order.** The builder attaches
23
+ * a `swapPayload` only for ERC20 sources — RUNE and native-gas-asset orders are
24
+ * plain deposits — so a co-signer keying off the swap payload alone sees a
25
+ * generic send to an opaque address with an opaque memo, and cannot tell what is
26
+ * being bought, where it pays out, or at what floor.
27
+ *
28
+ * Deriving the terms from `keysignPayload.memo` fixes that uniformly, because
29
+ * the memo is present on every source branch. It is also the *only* trustworthy
30
+ * source: the memo is the exact string THORChain executes, so terms read from it
31
+ * cannot disagree with the order that gets signed. A display field carried
32
+ * alongside the memo can — it is supplied by the initiating device, and a
33
+ * co-signer has no way to tell a mistaken one from a malicious one.
34
+ *
35
+ * Parsing is fail-closed on a malformed memo, but a caller reviewing an
36
+ * arbitrary payload wants "not a limit order" rather than a throw, so a memo
37
+ * that does not parse is reported as not-a-limit-order. Signing still rejects it:
38
+ * `buildLimitSwapKeysignPayload` parses the same memo and throws.
39
+ */
40
+ export declare const getKeysignLimitSwapOrder: ({ memo }: Pick<KeysignPayload, "memo">) => KeysignLimitSwapOrder | undefined;
41
+ //# sourceMappingURL=getKeysignLimitSwapOrder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getKeysignLimitSwapOrder.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/mpc/keysign/swap/getKeysignLimitSwapOrder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD,OAAO,EAEL,oBAAoB,EAGpB,mBAAmB,EAEpB,MAAM,gDAAgD,CAAA;AAIvD,OAAO,EAAE,cAAc,EAAE,MAAM,oDAAoD,CAAA;AASnF,MAAM,MAAM,qBAAqB,GAAG,mBAAmB,GAAG;IACxD,+EAA+E;IAC/E,WAAW,CAAC,EAAE,KAAK,CAAA;IACnB;;;;OAIG;IACH,sBAAsB,EAAE,MAAM,CAAA;IAC9B,mFAAmF;IACnF,WAAW,CAAC,EAAE,oBAAoB,CAAA;CACnC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,wBAAwB,GAAI,UAAU,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,KAAG,qBAAqB,GAAG,SAkBzG,CAAA"}
@@ -0,0 +1,50 @@
1
+ import { fromChainAmountDisplay } from '@vultisig/core-chain/amount/fromChainAmountExact';
2
+ import { Chain } from '@vultisig/core-chain/Chain';
3
+ import { chainFeeCoin } from '@vultisig/core-chain/coin/chainFeeCoin';
4
+ import { limitSwapExpiryHours, getLimitSwapIntervalBlocks, limitSwapMemoPrefix, parseLimitSwapMemo, } from '@vultisig/core-chain/swap/native/limitSwapMemo';
5
+ import { thorchainAssetPrefixToChain } from '@vultisig/core-chain/swap/native/thorchainMemoAsset';
6
+ import { attempt } from '@vultisig/lib-utils/attempt';
7
+ /** THORChain's fixed point for pool amounts, which the memo's LIM is expressed in. */
8
+ const thorchainDecimals = chainFeeCoin[Chain.THORChain].decimals;
9
+ const intervalBlocksToExpiryHours = Object.freeze(Object.fromEntries(limitSwapExpiryHours.map(hours => [getLimitSwapIntervalBlocks(hours), hours])));
10
+ /**
11
+ * Decode the limit order a keysign payload is about to place, for review.
12
+ *
13
+ * Returns `undefined` for any payload that is not a limit order, so a caller can
14
+ * branch on it directly.
15
+ *
16
+ * **This is how a *joining* device reviews a limit order.** The builder attaches
17
+ * a `swapPayload` only for ERC20 sources — RUNE and native-gas-asset orders are
18
+ * plain deposits — so a co-signer keying off the swap payload alone sees a
19
+ * generic send to an opaque address with an opaque memo, and cannot tell what is
20
+ * being bought, where it pays out, or at what floor.
21
+ *
22
+ * Deriving the terms from `keysignPayload.memo` fixes that uniformly, because
23
+ * the memo is present on every source branch. It is also the *only* trustworthy
24
+ * source: the memo is the exact string THORChain executes, so terms read from it
25
+ * cannot disagree with the order that gets signed. A display field carried
26
+ * alongside the memo can — it is supplied by the initiating device, and a
27
+ * co-signer has no way to tell a mistaken one from a malicious one.
28
+ *
29
+ * Parsing is fail-closed on a malformed memo, but a caller reviewing an
30
+ * arbitrary payload wants "not a limit order" rather than a throw, so a memo
31
+ * that does not parse is reported as not-a-limit-order. Signing still rejects it:
32
+ * `buildLimitSwapKeysignPayload` parses the same memo and throws.
33
+ */
34
+ export const getKeysignLimitSwapOrder = ({ memo }) => {
35
+ if (!memo?.startsWith(limitSwapMemoPrefix)) {
36
+ return undefined;
37
+ }
38
+ const parsed = attempt(() => parseLimitSwapMemo(memo));
39
+ if ('error' in parsed) {
40
+ return undefined;
41
+ }
42
+ const { data: order } = parsed;
43
+ return {
44
+ ...order,
45
+ targetChain: thorchainAssetPrefixToChain[order.targetAsset.split('.')[0].toUpperCase()],
46
+ minimumReceivedDecimal: fromChainAmountDisplay(order.limit, thorchainDecimals),
47
+ expiryHours: intervalBlocksToExpiryHours[order.intervalBlocks],
48
+ };
49
+ };
50
+ //# sourceMappingURL=getKeysignLimitSwapOrder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getKeysignLimitSwapOrder.js","sourceRoot":"","sources":["../../../../../../packages/core/mpc/keysign/swap/getKeysignLimitSwapOrder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kDAAkD,CAAA;AACzF,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AACrE,OAAO,EACL,oBAAoB,EAEpB,0BAA0B,EAC1B,mBAAmB,EAEnB,kBAAkB,GACnB,MAAM,gDAAgD,CAAA;AACvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,qDAAqD,CAAA;AACjG,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAIrD,sFAAsF;AACtF,MAAM,iBAAiB,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAA;AAEhE,MAAM,2BAA2B,GAA4D,MAAM,CAAC,MAAM,CACxG,MAAM,CAAC,WAAW,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,0BAA0B,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAClG,CAAA;AAeD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,EAAE,IAAI,EAAgC,EAAqC,EAAE;IACpH,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC3C,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAA;IACtD,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;QACtB,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAA;IAE9B,OAAO;QACL,GAAG,KAAK;QACR,WAAW,EAAE,2BAA2B,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACvF,sBAAsB,EAAE,sBAAsB,CAAC,KAAK,CAAC,KAAK,EAAE,iBAAiB,CAAC;QAC9E,WAAW,EAAE,2BAA2B,CAAC,KAAK,CAAC,cAAc,CAAC;KAC/D,CAAA;AACH,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vultisig/core-mpc",
3
- "version": "1.12.1",
3
+ "version": "1.14.0",
4
4
  "description": "MPC, keysign, and vault types shared across Vultisig clients",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -591,11 +591,21 @@
591
591
  "import": "./dist/keysign/swap/build.js",
592
592
  "default": "./dist/keysign/swap/build.js"
593
593
  },
594
+ "./keysign/swap/buildLimitSwapKeysignPayload": {
595
+ "types": "./dist/keysign/swap/buildLimitSwapKeysignPayload.d.ts",
596
+ "import": "./dist/keysign/swap/buildLimitSwapKeysignPayload.js",
597
+ "default": "./dist/keysign/swap/buildLimitSwapKeysignPayload.js"
598
+ },
594
599
  "./keysign/swap/cowswap/buildCowSwapApprovalSigningInput": {
595
600
  "types": "./dist/keysign/swap/cowswap/buildCowSwapApprovalSigningInput.d.ts",
596
601
  "import": "./dist/keysign/swap/cowswap/buildCowSwapApprovalSigningInput.js",
597
602
  "default": "./dist/keysign/swap/cowswap/buildCowSwapApprovalSigningInput.js"
598
603
  },
604
+ "./keysign/swap/getKeysignLimitSwapOrder": {
605
+ "types": "./dist/keysign/swap/getKeysignLimitSwapOrder.d.ts",
606
+ "import": "./dist/keysign/swap/getKeysignLimitSwapOrder.js",
607
+ "default": "./dist/keysign/swap/getKeysignLimitSwapOrder.js"
608
+ },
599
609
  "./keysign/swap/getKeysignSwapPayload": {
600
610
  "types": "./dist/keysign/swap/getKeysignSwapPayload.d.ts",
601
611
  "import": "./dist/keysign/swap/getKeysignSwapPayload.js",
@@ -1063,13 +1073,13 @@
1063
1073
  },
1064
1074
  "dependencies": {
1065
1075
  "7z-wasm": "^1.2.0",
1066
- "@bufbuild/protobuf": "^2.12.0",
1076
+ "@bufbuild/protobuf": "^2.13.0",
1067
1077
  "@cosmjs/encoding": "^0.39.0",
1068
- "@mysten/sui": "^2.20.3",
1078
+ "@mysten/sui": "^2.22.1",
1069
1079
  "@noble/hashes": "^1.8.0",
1070
1080
  "@solana/web3.js": "^1.98.4",
1071
1081
  "@trustwallet/wallet-core": "^4.7.0",
1072
- "@vultisig/core-chain": "2.27.0",
1082
+ "@vultisig/core-chain": "2.29.0",
1073
1083
  "@vultisig/core-config": "0.9.1",
1074
1084
  "@vultisig/lib-dkls": "0.9.0",
1075
1085
  "@vultisig/lib-mldsa": "0.9.0",