@vultisig/core-chain 1.1.0 → 1.2.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 (102) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/amount/toChainAmount.d.ts +6 -1
  3. package/dist/amount/toChainAmount.d.ts.map +1 -1
  4. package/dist/amount/toChainAmount.js +88 -0
  5. package/dist/amount/toChainAmount.js.map +1 -1
  6. package/dist/chains/cosmos/qbtc/claim/BtcAddressType.d.ts +7 -0
  7. package/dist/chains/cosmos/qbtc/claim/BtcAddressType.d.ts.map +1 -0
  8. package/dist/chains/cosmos/qbtc/claim/BtcAddressType.js +9 -0
  9. package/dist/chains/cosmos/qbtc/claim/BtcAddressType.js.map +1 -0
  10. package/dist/chains/cosmos/qbtc/claim/ClaimableUtxo.d.ts +8 -0
  11. package/dist/chains/cosmos/qbtc/claim/ClaimableUtxo.d.ts.map +1 -0
  12. package/dist/chains/cosmos/qbtc/claim/ClaimableUtxo.js +2 -0
  13. package/dist/chains/cosmos/qbtc/claim/ClaimableUtxo.js.map +1 -0
  14. package/dist/chains/cosmos/qbtc/claim/broadcastClaimTx.d.ts +25 -0
  15. package/dist/chains/cosmos/qbtc/claim/broadcastClaimTx.d.ts.map +1 -0
  16. package/dist/chains/cosmos/qbtc/claim/broadcastClaimTx.js +43 -0
  17. package/dist/chains/cosmos/qbtc/claim/broadcastClaimTx.js.map +1 -0
  18. package/dist/chains/cosmos/qbtc/claim/buildClaimTx.d.ts +26 -0
  19. package/dist/chains/cosmos/qbtc/claim/buildClaimTx.d.ts.map +1 -0
  20. package/dist/chains/cosmos/qbtc/claim/buildClaimTx.js +57 -0
  21. package/dist/chains/cosmos/qbtc/claim/buildClaimTx.js.map +1 -0
  22. package/dist/chains/cosmos/qbtc/claim/computeClaimHashes.d.ts +49 -0
  23. package/dist/chains/cosmos/qbtc/claim/computeClaimHashes.d.ts.map +1 -0
  24. package/dist/chains/cosmos/qbtc/claim/computeClaimHashes.js +85 -0
  25. package/dist/chains/cosmos/qbtc/claim/computeClaimHashes.js.map +1 -0
  26. package/dist/chains/cosmos/qbtc/claim/detectBtcAddressType.d.ts +14 -0
  27. package/dist/chains/cosmos/qbtc/claim/detectBtcAddressType.d.ts.map +1 -0
  28. package/dist/chains/cosmos/qbtc/claim/detectBtcAddressType.js +31 -0
  29. package/dist/chains/cosmos/qbtc/claim/detectBtcAddressType.js.map +1 -0
  30. package/dist/chains/cosmos/qbtc/claim/getClaimWithProofDisabled.d.ts +3 -0
  31. package/dist/chains/cosmos/qbtc/claim/getClaimWithProofDisabled.d.ts.map +1 -0
  32. package/dist/chains/cosmos/qbtc/claim/getClaimWithProofDisabled.js +13 -0
  33. package/dist/chains/cosmos/qbtc/claim/getClaimWithProofDisabled.js.map +1 -0
  34. package/dist/chains/cosmos/qbtc/claim/getClaimableUtxos.d.ts +14 -0
  35. package/dist/chains/cosmos/qbtc/claim/getClaimableUtxos.d.ts.map +1 -0
  36. package/dist/chains/cosmos/qbtc/claim/getClaimableUtxos.js +22 -0
  37. package/dist/chains/cosmos/qbtc/claim/getClaimableUtxos.js.map +1 -0
  38. package/dist/chains/cosmos/qbtc/claim/proofService.d.ts +50 -0
  39. package/dist/chains/cosmos/qbtc/claim/proofService.d.ts.map +1 -0
  40. package/dist/chains/cosmos/qbtc/claim/proofService.js +71 -0
  41. package/dist/chains/cosmos/qbtc/claim/proofService.js.map +1 -0
  42. package/dist/chains/cosmos/thor/lp/halts.d.ts +56 -0
  43. package/dist/chains/cosmos/thor/lp/halts.d.ts.map +1 -0
  44. package/dist/chains/cosmos/thor/lp/halts.js +95 -0
  45. package/dist/chains/cosmos/thor/lp/halts.js.map +1 -0
  46. package/dist/chains/cosmos/thor/lp/index.d.ts +34 -11
  47. package/dist/chains/cosmos/thor/lp/index.d.ts.map +1 -1
  48. package/dist/chains/cosmos/thor/lp/index.js +9 -15
  49. package/dist/chains/cosmos/thor/lp/index.js.map +1 -1
  50. package/dist/chains/cosmos/thor/lp/lockup.d.ts +47 -0
  51. package/dist/chains/cosmos/thor/lp/lockup.d.ts.map +1 -0
  52. package/dist/chains/cosmos/thor/lp/lockup.js +56 -0
  53. package/dist/chains/cosmos/thor/lp/lockup.js.map +1 -0
  54. package/dist/chains/cosmos/thor/lp/lpChainMap.d.ts +25 -0
  55. package/dist/chains/cosmos/thor/lp/lpChainMap.d.ts.map +1 -0
  56. package/dist/chains/cosmos/thor/lp/lpChainMap.js +30 -0
  57. package/dist/chains/cosmos/thor/lp/lpChainMap.js.map +1 -0
  58. package/dist/chains/cosmos/thor/lp/math.d.ts +129 -0
  59. package/dist/chains/cosmos/thor/lp/math.d.ts.map +1 -0
  60. package/dist/chains/cosmos/thor/lp/math.js +227 -0
  61. package/dist/chains/cosmos/thor/lp/math.js.map +1 -0
  62. package/dist/chains/cosmos/thor/lp/memberPool.d.ts +4 -0
  63. package/dist/chains/cosmos/thor/lp/memberPool.d.ts.map +1 -0
  64. package/dist/chains/cosmos/thor/lp/memberPool.js +24 -0
  65. package/dist/chains/cosmos/thor/lp/memberPool.js.map +1 -0
  66. package/dist/chains/cosmos/thor/lp/memo.d.ts +38 -17
  67. package/dist/chains/cosmos/thor/lp/memo.d.ts.map +1 -1
  68. package/dist/chains/cosmos/thor/lp/memo.js +40 -16
  69. package/dist/chains/cosmos/thor/lp/memo.js.map +1 -1
  70. package/dist/chains/cosmos/thor/lp/pairing.d.ts +30 -0
  71. package/dist/chains/cosmos/thor/lp/pairing.d.ts.map +1 -0
  72. package/dist/chains/cosmos/thor/lp/pairing.js +44 -0
  73. package/dist/chains/cosmos/thor/lp/pairing.js.map +1 -0
  74. package/dist/chains/cosmos/thor/lp/payload.d.ts +30 -10
  75. package/dist/chains/cosmos/thor/lp/payload.d.ts.map +1 -1
  76. package/dist/chains/cosmos/thor/lp/payload.js +30 -18
  77. package/dist/chains/cosmos/thor/lp/payload.js.map +1 -1
  78. package/dist/chains/cosmos/thor/lp/position.d.ts +15 -22
  79. package/dist/chains/cosmos/thor/lp/position.d.ts.map +1 -1
  80. package/dist/chains/cosmos/thor/lp/position.js +82 -35
  81. package/dist/chains/cosmos/thor/lp/position.js.map +1 -1
  82. package/dist/chains/cosmos/thor/lp/positions.d.ts +15 -0
  83. package/dist/chains/cosmos/thor/lp/positions.d.ts.map +1 -0
  84. package/dist/chains/cosmos/thor/lp/positions.js +47 -0
  85. package/dist/chains/cosmos/thor/lp/positions.js.map +1 -0
  86. package/dist/chains/cosmos/thor/lp/types.d.ts +45 -0
  87. package/dist/chains/cosmos/thor/lp/types.d.ts.map +1 -0
  88. package/dist/chains/cosmos/thor/lp/types.js +2 -0
  89. package/dist/chains/cosmos/thor/lp/types.js.map +1 -0
  90. package/dist/chains/cosmos/thor/lp/validation.d.ts +32 -7
  91. package/dist/chains/cosmos/thor/lp/validation.d.ts.map +1 -1
  92. package/dist/chains/cosmos/thor/lp/validation.js +76 -11
  93. package/dist/chains/cosmos/thor/lp/validation.js.map +1 -1
  94. package/dist/chains/utxo/tx/buildSignBitcoinFromPsbt.d.ts +21 -0
  95. package/dist/chains/utxo/tx/buildSignBitcoinFromPsbt.d.ts.map +1 -0
  96. package/dist/chains/utxo/tx/buildSignBitcoinFromPsbt.js +182 -0
  97. package/dist/chains/utxo/tx/buildSignBitcoinFromPsbt.js.map +1 -0
  98. package/package.json +90 -5
  99. package/dist/chains/cosmos/thor/lp/affiliate.d.ts +0 -16
  100. package/dist/chains/cosmos/thor/lp/affiliate.d.ts.map +0 -1
  101. package/dist/chains/cosmos/thor/lp/affiliate.js +0 -16
  102. package/dist/chains/cosmos/thor/lp/affiliate.js.map +0 -1
@@ -0,0 +1,44 @@
1
+ import { Chain } from '@vultisig/core-chain/Chain';
2
+ import { chainPrefixToChain } from './lpChainMap.js';
3
+ import { assertValidPoolId } from './pools.js';
4
+ /**
5
+ * Resolve the paired-address for an LP add based on which side of the
6
+ * pool the caller is depositing.
7
+ *
8
+ * - `side: 'rune'` (depositing RUNE on THORChain): returns the vault's L1
9
+ * address on the pool's ASSET chain. E.g. `BTC.BTC` → vault's BTC
10
+ * address.
11
+ * - `side: 'asset'` (depositing L1 asset): returns the vault's THORChain
12
+ * address (`thor1...`).
13
+ *
14
+ * Matches vultisig-ios `FunctionCallAddThorLP.prefillPairedAddressForPool`
15
+ * and vultisig-windows (the extension) `ThorLpSpecific.tsx`
16
+ * behavior exactly — both always auto-populate the paired address when the
17
+ * vault has the required address, producing a symmetric-pending memo.
18
+ *
19
+ * Returns `undefined` when the vault map does not contain the required
20
+ * address. The caller decides whether to:
21
+ * - fall back to a pure asymmetric deposit (`+:POOL` with no paired
22
+ * address), or
23
+ * - surface an error ("add the other chain to your vault first").
24
+ */
25
+ export const resolvePairedAddressForLpAdd = ({ pool, side, vaultAddresses, }) => {
26
+ assertValidPoolId(pool);
27
+ // Guard against unknown pool prefixes on BOTH sides — the pool id regex
28
+ // accepts `ZZZ.ABC` but `chainPrefixToChain` is the source of truth for
29
+ // THORChain-supported chains. If we can't resolve the prefix we refuse
30
+ // to auto-pair either way; the caller can still fall back to a pure
31
+ // asym memo if they want.
32
+ const [chainPrefix] = pool.split('.');
33
+ if (!chainPrefix)
34
+ return undefined;
35
+ const assetChain = chainPrefixToChain(chainPrefix);
36
+ if (!assetChain)
37
+ return undefined;
38
+ if (side === 'asset') {
39
+ return vaultAddresses[Chain.THORChain];
40
+ }
41
+ // side === 'rune' — need the vault's address on the pool's asset chain
42
+ return vaultAddresses[assetChain];
43
+ };
44
+ //# sourceMappingURL=pairing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairing.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/pairing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAM3C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,EAC3C,IAAI,EACJ,IAAI,EACJ,cAAc,GAKf,EAAsB,EAAE;IACvB,iBAAiB,CAAC,IAAI,CAAC,CAAA;IAEvB,wEAAwE;IACxE,wEAAwE;IACxE,uEAAuE;IACvE,oEAAoE;IACpE,0BAA0B;IAC1B,MAAM,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACrC,IAAI,CAAC,WAAW;QAAE,OAAO,SAAS,CAAA;IAClC,MAAM,UAAU,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAA;IAClD,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAA;IAEjC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,cAAc,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACxC,CAAC;IAED,uEAAuE;IACvE,OAAO,cAAc,CAAC,UAAU,CAAC,CAAA;AACnC,CAAC,CAAA"}
@@ -1,11 +1,15 @@
1
1
  /**
2
2
  * Flat unsigned-transaction payload for an asymmetric RUNE-side LP add.
3
3
  *
4
- * Shape stays single-nesting-level on purpose: this object is what flows
5
- * through the agent backend's SSE `tx_ready` event, and the audit
6
- * (2026-04-09) flagged tool result flattening as a known wire-level hazard
7
- * for nested fields. Every consumer (MCP tool result, backend SSE emit, app
4
+ * Shape stays single-nesting-level on purpose: this object flows through
5
+ * the agent backend's SSE `tx_ready` event, and the 2026-04-09 audit
6
+ * flagged tool result flattening as a known wire-level hazard for nested
7
+ * fields. Every consumer (MCP tool result, backend SSE emit, app
8
8
  * `parseServerTx`) reads the same flat keys.
9
+ *
10
+ * v2 wire format drops the `affiliate` / `affiliateBps` fields. Matches
11
+ * vultisig-ios and vultisig-windows (the extension) — neither ships an
12
+ * affiliate on LP memos.
9
13
  */
10
14
  export type ThorchainLpAddPayload = {
11
15
  kind: 'thorchain_lp_add';
@@ -17,10 +21,11 @@ export type ThorchainLpAddPayload = {
17
21
  memo: string;
18
22
  /** Canonical pool id, denormalized for display. */
19
23
  pool: string;
20
- /** Affiliate THORName, denormalized for display. */
21
- affiliate: string;
22
- /** Affiliate fee in basis points, denormalized for display. */
23
- affiliateBps: number;
24
+ /**
25
+ * Paired L1 address embedded in the memo, if any. Denormalized for
26
+ * display so consumers don't have to re-parse the memo.
27
+ */
28
+ pairedAddress?: string;
24
29
  };
25
30
  export type ThorchainLpRemovePayload = {
26
31
  kind: 'thorchain_lp_remove';
@@ -32,15 +37,30 @@ export type ThorchainLpRemovePayload = {
32
37
  memo: string;
33
38
  pool: string;
34
39
  basisPoints: number;
40
+ /**
41
+ * Asym-withdraw target asset, if any. Denormalized for display.
42
+ */
43
+ withdrawToAsset?: string;
35
44
  };
36
45
  export type BuildThorchainLpAddPayloadInput = {
37
46
  pool: string;
38
47
  amountRuneBaseUnits: string;
48
+ /**
49
+ * Optional paired address. When provided, embedded in the memo (matching
50
+ * iOS / Windows-extension auto-pair behavior) and denormalized on the
51
+ * payload for display.
52
+ */
53
+ pairedAddress?: string;
39
54
  };
40
- export declare const buildThorchainLpAddPayload: ({ pool, amountRuneBaseUnits, }: BuildThorchainLpAddPayloadInput) => ThorchainLpAddPayload;
55
+ export declare const buildThorchainLpAddPayload: ({ pool, amountRuneBaseUnits, pairedAddress, }: BuildThorchainLpAddPayloadInput) => ThorchainLpAddPayload;
41
56
  export type BuildThorchainLpRemovePayloadInput = {
42
57
  pool: string;
43
58
  basisPoints: number;
59
+ /**
60
+ * Optional asym-withdraw target. Pass the short asset ticker (e.g. `BTC`),
61
+ * not the full pool id.
62
+ */
63
+ withdrawToAsset?: string;
44
64
  };
45
- export declare const buildThorchainLpRemovePayload: ({ pool, basisPoints, }: BuildThorchainLpRemovePayloadInput) => ThorchainLpRemovePayload;
65
+ export declare const buildThorchainLpRemovePayload: ({ pool, basisPoints, withdrawToAsset, }: BuildThorchainLpRemovePayloadInput) => ThorchainLpRemovePayload;
46
66
  //# sourceMappingURL=payload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/payload.ts"],"names":[],"mappings":"AAMA;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,kBAAkB,CAAA;IACxB,KAAK,EAAE,WAAW,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;IACd,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAA;IACjB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,qBAAqB,CAAA;IAC3B,KAAK,EAAE,WAAW,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAA;IACd,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAeD,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,MAAM,CAAA;IACZ,mBAAmB,EAAE,MAAM,CAAA;CAC5B,CAAA;AAED,eAAO,MAAM,0BAA0B,GAAI,gCAGxC,+BAA+B,KAAG,qBAgBpC,CAAA;AAED,MAAM,MAAM,kCAAkC,GAAG;IAC/C,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,eAAO,MAAM,6BAA6B,GAAI,wBAG3C,kCAAkC,KAAG,wBAQtC,CAAA"}
1
+ {"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/payload.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,kBAAkB,CAAA;IACxB,KAAK,EAAE,WAAW,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;IACd,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,qBAAqB,CAAA;IAC3B,KAAK,EAAE,WAAW,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAA;IACd,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAgBD,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,MAAM,CAAA;IACZ,mBAAmB,EAAE,MAAM,CAAA;IAC3B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,eAAO,MAAM,0BAA0B,GAAI,+CAIxC,+BAA+B,KAAG,qBAgBpC,CAAA;AAED,MAAM,MAAM,kCAAkC,GAAG;IAC/C,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,eAAO,MAAM,6BAA6B,GAAI,yCAI3C,kCAAkC,KAAG,wBAwBvC,CAAA"}
@@ -1,37 +1,49 @@
1
- import { VULTISIG_AFFILIATE_LP_BPS, VULTISIG_AFFILIATE_NAME, } from './affiliate.js';
2
1
  import { addLpMemo, removeLpMemo } from './memo.js';
3
2
  /**
4
3
  * Dust amount used for LP removes.
5
4
  *
6
- * Reference: vultisig-windows/core/ui/vault/deposit/keysignPayload/build.ts
7
- * sends 0.02 RUNE on LP remove transactions — the on-chain amount is just
8
- * dust to make the cosmos message valid; the actual withdraw fraction lives
9
- * inside the memo (`-:POOL:BPS`).
5
+ * Reference: vultisig-windows (the extension)
6
+ * `core/ui/vault/deposit/keysignPayload/build.ts` uses 0.02 RUNE as the
7
+ * dust amount on LP remove transactions the on-chain amount is just
8
+ * dust to make the cosmos message valid; the actual withdraw fraction
9
+ * lives inside the memo (`-:POOL:BPS`).
10
10
  */
11
11
  const LP_REMOVE_DUST_RUNE_BASE_UNITS = '2000000';
12
12
  const isPositiveBaseUnitString = (value) => /^\d+$/.test(value) && BigInt(value) > 0n;
13
- export const buildThorchainLpAddPayload = ({ pool, amountRuneBaseUnits, }) => {
13
+ export const buildThorchainLpAddPayload = ({ pool, amountRuneBaseUnits, pairedAddress, }) => {
14
14
  if (!isPositiveBaseUnitString(amountRuneBaseUnits)) {
15
15
  throw new Error(`buildThorchainLpAddPayload: amountRuneBaseUnits must be a positive integer string, got ${amountRuneBaseUnits}`);
16
16
  }
17
+ const memo = addLpMemo({ pool, pairedAddress });
17
18
  return {
18
19
  kind: 'thorchain_lp_add',
19
20
  chain: 'THORChain',
20
21
  denom: 'rune',
21
22
  amount: amountRuneBaseUnits,
22
- memo: addLpMemo({ pool }),
23
+ memo,
23
24
  pool,
24
- affiliate: VULTISIG_AFFILIATE_NAME,
25
- affiliateBps: VULTISIG_AFFILIATE_LP_BPS,
25
+ ...(pairedAddress ? { pairedAddress } : {}),
26
+ };
27
+ };
28
+ export const buildThorchainLpRemovePayload = ({ pool, basisPoints, withdrawToAsset, }) => {
29
+ // removeLpMemo validates this too, but fail fast at the payload
30
+ // boundary so callers see a consistent error shape with the add
31
+ // builder (which validates amountRuneBaseUnits up-front).
32
+ if (!Number.isInteger(basisPoints) ||
33
+ basisPoints < 1 ||
34
+ basisPoints > 10000) {
35
+ throw new Error(`buildThorchainLpRemovePayload: basisPoints must be an integer in [1, 10000], got ${basisPoints}`);
36
+ }
37
+ const memo = removeLpMemo({ pool, basisPoints, withdrawToAsset });
38
+ return {
39
+ kind: 'thorchain_lp_remove',
40
+ chain: 'THORChain',
41
+ denom: 'rune',
42
+ amount: LP_REMOVE_DUST_RUNE_BASE_UNITS,
43
+ memo,
44
+ pool,
45
+ basisPoints,
46
+ ...(withdrawToAsset ? { withdrawToAsset } : {}),
26
47
  };
27
48
  };
28
- export const buildThorchainLpRemovePayload = ({ pool, basisPoints, }) => ({
29
- kind: 'thorchain_lp_remove',
30
- chain: 'THORChain',
31
- denom: 'rune',
32
- amount: LP_REMOVE_DUST_RUNE_BASE_UNITS,
33
- memo: removeLpMemo({ pool, basisPoints }),
34
- pool,
35
- basisPoints,
36
- });
37
49
  //# sourceMappingURL=payload.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"payload.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/payload.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAuChD;;;;;;;GAOG;AACH,MAAM,8BAA8B,GAAG,SAAS,CAAA;AAEhD,MAAM,wBAAwB,GAAG,CAAC,KAAa,EAAW,EAAE,CAC1D,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;AAO3C,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,EACzC,IAAI,EACJ,mBAAmB,GACa,EAAyB,EAAE;IAC3D,IAAI,CAAC,wBAAwB,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CACb,0FAA0F,mBAAmB,EAAE,CAChH,CAAA;IACH,CAAC;IACD,OAAO;QACL,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,mBAAmB;QAC3B,IAAI,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;QACzB,IAAI;QACJ,SAAS,EAAE,uBAAuB;QAClC,YAAY,EAAE,yBAAyB;KACxC,CAAA;AACH,CAAC,CAAA;AAOD,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,EAC5C,IAAI,EACJ,WAAW,GACwB,EAA4B,EAAE,CAAC,CAAC;IACnE,IAAI,EAAE,qBAAqB;IAC3B,KAAK,EAAE,WAAW;IAClB,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,8BAA8B;IACtC,IAAI,EAAE,YAAY,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IACzC,IAAI;IACJ,WAAW;CACZ,CAAC,CAAA"}
1
+ {"version":3,"file":"payload.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/payload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAgDhD;;;;;;;;GAQG;AACH,MAAM,8BAA8B,GAAG,SAAS,CAAA;AAEhD,MAAM,wBAAwB,GAAG,CAAC,KAAa,EAAW,EAAE,CAC1D,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;AAa3C,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,EACzC,IAAI,EACJ,mBAAmB,EACnB,aAAa,GACmB,EAAyB,EAAE;IAC3D,IAAI,CAAC,wBAAwB,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CACb,0FAA0F,mBAAmB,EAAE,CAChH,CAAA;IACH,CAAC;IACD,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAA;IAC/C,OAAO;QACL,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,mBAAmB;QAC3B,IAAI;QACJ,IAAI;QACJ,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5C,CAAA;AACH,CAAC,CAAA;AAYD,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,EAC5C,IAAI,EACJ,WAAW,EACX,eAAe,GACoB,EAA4B,EAAE;IACjE,gEAAgE;IAChE,gEAAgE;IAChE,0DAA0D;IAC1D,IACE,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC;QAC9B,WAAW,GAAG,CAAC;QACf,WAAW,GAAG,KAAK,EACnB,CAAC;QACD,MAAM,IAAI,KAAK,CACb,oFAAoF,WAAW,EAAE,CAClG,CAAA;IACH,CAAC;IACD,MAAM,IAAI,GAAG,YAAY,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,CAAA;IACjE,OAAO;QACL,IAAI,EAAE,qBAAqB;QAC3B,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,8BAA8B;QACtC,IAAI;QACJ,IAAI;QACJ,WAAW;QACX,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAA;AACH,CAAC,CAAA"}
@@ -1,30 +1,23 @@
1
- /**
2
- * Subset of a Midgard `/v2/member/{address}` pool entry. Midgard returns
3
- * many more fields per position — we keep just the ones the agent stack
4
- * surfaces in chat (units, added amounts, pending state, last-add timestamp).
5
- */
6
- export type ThorchainLpPosition = {
7
- pool: string;
8
- liquidityUnits: string;
9
- runeAdded: string;
10
- assetAdded: string;
11
- runePending: string;
12
- assetPending: string;
13
- runeAddress: string;
14
- assetAddress: string;
15
- /** Unix seconds (Midgard returns it as a string). */
16
- dateLastAdded: string;
17
- /**
18
- * True when either side has a non-zero pending amount. Common for
19
- * asymmetric adds that THORChain has not yet credited.
20
- */
21
- isPending: boolean;
22
- };
1
+ import type { ThorchainLpPosition } from './types.js';
2
+ export type { ThorchainLpPosition } from './types.js';
23
3
  export type GetThorchainLpPositionInput = {
24
4
  /** bech32 thor1... address (the RUNE side of the position). */
25
5
  thorAddress: string;
26
6
  /** Canonical pool id to look up. */
27
7
  pool: string;
28
8
  };
9
+ /**
10
+ * Fetch a single LP position from Midgard.
11
+ *
12
+ * Returns `null` when:
13
+ * - the address has no positions at all (Midgard returns 404), or
14
+ * - the address has positions but none in the requested pool.
15
+ */
29
16
  export declare const getThorchainLpPosition: ({ thorAddress, pool, }: GetThorchainLpPositionInput) => Promise<ThorchainLpPosition | null>;
17
+ /**
18
+ * Fetch a single LP position directly from thornode. Catches the
19
+ * pending-only case Midgard doesn't surface. Returns null when the
20
+ * position is truly empty (no units, no pending on either side).
21
+ */
22
+ export declare const getThorchainLpPositionFromThornode: ({ thorAddress, pool, }: GetThorchainLpPositionInput) => Promise<ThorchainLpPosition | null>;
30
23
  //# sourceMappingURL=position.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"position.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/position.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAwCD,MAAM,MAAM,2BAA2B,GAAG;IACxC,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAA;IACnB,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAkBD,eAAO,MAAM,sBAAsB,GAAU,wBAG1C,2BAA2B,KAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAelE,CAAA"}
1
+ {"version":3,"file":"position.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/position.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAqB,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAErE,YAAY,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAElD,MAAM,MAAM,2BAA2B,GAAG;IACxC,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAA;IACnB,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAWD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAU,wBAG1C,2BAA2B,KAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CA2BlE,CAAA;AAaD;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,GAAU,wBAGtD,2BAA2B,KAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAkDlE,CAAA"}
@@ -1,35 +1,9 @@
1
+ import { Chain } from '@vultisig/core-chain/Chain';
2
+ import { cosmosRpcUrl } from '@vultisig/core-chain/chains/cosmos/cosmosRpcUrl';
1
3
  import { HttpResponseError } from '@vultisig/lib-utils/fetch/HttpResponseError';
2
4
  import { queryUrl } from '@vultisig/lib-utils/query/queryUrl';
5
+ import { isNonZeroBaseUnit, normalizeMemberPool } from './memberPool.js';
3
6
  import { assertValidPoolId, thorchainMidgardBaseUrl } from './pools.js';
4
- const isNonZero = (s) => {
5
- if (!s)
6
- return false;
7
- try {
8
- return BigInt(s) > 0n;
9
- }
10
- catch {
11
- return false;
12
- }
13
- };
14
- const normalizeMemberPool = (raw) => ({
15
- pool: raw.pool ?? '',
16
- liquidityUnits: raw.liquidityUnits ?? '0',
17
- runeAdded: raw.runeAdded ?? '0',
18
- assetAdded: raw.assetAdded ?? '0',
19
- runePending: raw.runePending ?? '0',
20
- assetPending: raw.assetPending ?? '0',
21
- runeAddress: raw.runeAddress ?? '',
22
- assetAddress: raw.assetAddress ?? '',
23
- dateLastAdded: raw.dateLastAdded ?? '0',
24
- isPending: isNonZero(raw.runePending) || isNonZero(raw.assetPending),
25
- });
26
- /**
27
- * Fetch a single LP position from Midgard.
28
- *
29
- * Returns `null` when:
30
- * - the address has no positions at all (Midgard returns 404), or
31
- * - the address has positions but none in the requested pool.
32
- */
33
7
  /**
34
8
  * Detect a 404 from queryUrl by reading the typed `HttpResponseError.status`
35
9
  * field that `@vultisig/lib-utils` `assertFetchResponse` now throws. The
@@ -37,22 +11,95 @@ const normalizeMemberPool = (raw) => ({
37
11
  * but was brittle to wording changes. See NeoMakinG's PR #236 review note.
38
12
  */
39
13
  const isMidgardNotFoundError = (err) => err instanceof HttpResponseError && err.status === 404;
14
+ /**
15
+ * Fetch a single LP position from Midgard.
16
+ *
17
+ * Returns `null` when:
18
+ * - the address has no positions at all (Midgard returns 404), or
19
+ * - the address has positions but none in the requested pool.
20
+ */
40
21
  export const getThorchainLpPosition = async ({ thorAddress, pool, }) => {
41
22
  assertValidPoolId(pool);
42
23
  const url = `${thorchainMidgardBaseUrl}/v2/member/${encodeURIComponent(thorAddress)}`;
24
+ let midgardNotFound = false;
25
+ let raw = {};
26
+ try {
27
+ raw = await queryUrl(url);
28
+ }
29
+ catch (err) {
30
+ if (isMidgardNotFoundError(err)) {
31
+ midgardNotFound = true;
32
+ }
33
+ else {
34
+ throw err;
35
+ }
36
+ }
37
+ if (!midgardNotFound) {
38
+ const pools = Array.isArray(raw.pools) ? raw.pools : [];
39
+ const found = pools.find(p => p.pool === pool);
40
+ if (found)
41
+ return normalizeMemberPool(found);
42
+ }
43
+ // Midgard has no record of this pool for this address. THORChain
44
+ // asymmetric adds land as `pending_rune` / `pending_asset` on thornode
45
+ // and stay off Midgard until the counter-side materializes the LP (or a
46
+ // pending-timeout flips the state). A pending-only position is still
47
+ // fully withdrawable via `-:POOL:BPS` — the handler refunds the pending
48
+ // side. Falling back to thornode here so the LLM sees the position and
49
+ // doesn't wrongly tell the user "nothing to withdraw".
50
+ return getThorchainLpPositionFromThornode({ thorAddress, pool });
51
+ };
52
+ /**
53
+ * Fetch a single LP position directly from thornode. Catches the
54
+ * pending-only case Midgard doesn't surface. Returns null when the
55
+ * position is truly empty (no units, no pending on either side).
56
+ */
57
+ export const getThorchainLpPositionFromThornode = async ({ thorAddress, pool, }) => {
58
+ assertValidPoolId(pool);
59
+ const url = `${cosmosRpcUrl[Chain.THORChain]}/thorchain/pool/${encodeURIComponent(pool)}` +
60
+ `/liquidity_provider/${encodeURIComponent(thorAddress)}`;
43
61
  let raw;
44
62
  try {
45
63
  raw = await queryUrl(url);
46
64
  }
47
65
  catch (err) {
48
- // Midgard returns 404 for any address it has not indexed yet — treat as
49
- // "no position". Other errors bubble.
50
- if (isMidgardNotFoundError(err))
66
+ // thornode returns 404 when no LP record exists for the address on
67
+ // this pool. Treat as "no position" same as Midgard.
68
+ if (err instanceof HttpResponseError && err.status === 404)
51
69
  return null;
52
70
  throw err;
53
71
  }
54
- const pools = Array.isArray(raw.pools) ? raw.pools : [];
55
- const found = pools.find(p => p.pool === pool);
56
- return found ? normalizeMemberPool(found) : null;
72
+ const units = raw.units ?? '0';
73
+ const pendingRune = raw.pending_rune ?? '0';
74
+ const pendingAsset = raw.pending_asset ?? '0';
75
+ // Thornode always returns the endpoint with zeroed fields after a full
76
+ // withdraw, so explicitly guard "everything is zero" as "no position".
77
+ if (!isNonZeroBaseUnit(units) &&
78
+ !isNonZeroBaseUnit(pendingRune) &&
79
+ !isNonZeroBaseUnit(pendingAsset)) {
80
+ return null;
81
+ }
82
+ return {
83
+ pool: raw.asset ?? pool,
84
+ liquidityUnits: units,
85
+ // Thornode doesn't track historical added amounts — those are a
86
+ // Midgard-only enrichment. Surface them as 0; the caller can still
87
+ // act on units/pending.
88
+ runeAdded: '0',
89
+ assetAdded: '0',
90
+ runePending: pendingRune,
91
+ assetPending: pendingAsset,
92
+ runeAddress: raw.rune_address ?? thorAddress,
93
+ assetAddress: raw.asset_address ?? '',
94
+ // Thornode exposes the last-add block height, not a Unix timestamp.
95
+ // Keep `dateLastAdded` semantically Unix-seconds-or-0 and expose the
96
+ // block height via the dedicated `lastAddHeight` field so lockup
97
+ // checks can use either source.
98
+ dateLastAdded: '0',
99
+ lastAddHeight: typeof raw.last_add_height === 'number'
100
+ ? String(raw.last_add_height)
101
+ : '',
102
+ isPending: isNonZeroBaseUnit(pendingRune) || isNonZeroBaseUnit(pendingAsset),
103
+ };
57
104
  };
58
105
  //# sourceMappingURL=position.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"position.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/position.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAA;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAA;AAE7D,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA;AAyCpE,MAAM,SAAS,GAAG,CAAC,CAAqB,EAAW,EAAE;IACnD,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAA;IACpB,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC,CAAA;AAED,MAAM,mBAAmB,GAAG,CAAC,GAAkB,EAAuB,EAAE,CAAC,CAAC;IACxE,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE;IACpB,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,GAAG;IACzC,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG;IAC/B,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG;IACjC,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,GAAG;IACnC,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,GAAG;IACrC,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE;IAClC,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,EAAE;IACpC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,GAAG;IACvC,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC;CACrE,CAAC,CAAA;AASF;;;;;;GAMG;AACH;;;;;GAKG;AACH,MAAM,sBAAsB,GAAG,CAAC,GAAY,EAAW,EAAE,CACvD,GAAG,YAAY,iBAAiB,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAA;AAExD,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EAAE,EAC3C,WAAW,EACX,IAAI,GACwB,EAAuC,EAAE;IACrE,iBAAiB,CAAC,IAAI,CAAC,CAAA;IACvB,MAAM,GAAG,GAAG,GAAG,uBAAuB,cAAc,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAA;IACrF,IAAI,GAAsB,CAAA;IAC1B,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAoB,GAAG,CAAC,CAAA;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wEAAwE;QACxE,sCAAsC;QACtC,IAAI,sBAAsB,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAA;QAC5C,MAAM,GAAG,CAAA;IACX,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IACvD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;IAC9C,OAAO,KAAK,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAClD,CAAC,CAAA"}
1
+ {"version":3,"file":"position.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/position.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { ThorchainLpPosition } from './types.js';
2
+ /**
3
+ * Fetch every LP position for a THORChain address in a single Midgard call.
4
+ *
5
+ * Returns an empty array when:
6
+ * - the address has no positions at all (Midgard returns 404), or
7
+ * - Midgard returns a body without a `pools` array (defensive).
8
+ *
9
+ * Prefer this over calling `getThorchainLpPosition` N times — one HTTP
10
+ * round-trip regardless of position count.
11
+ */
12
+ export declare const getThorchainLpPositions: ({ thorAddress, }: {
13
+ thorAddress: string;
14
+ }) => Promise<ThorchainLpPosition[]>;
15
+ //# sourceMappingURL=positions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"positions.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/positions.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAqB,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAErE;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,GAAU,kBAE3C;IACD,WAAW,EAAE,MAAM,CAAA;CACpB,KAAG,OAAO,CAAC,mBAAmB,EAAE,CAiChC,CAAA"}
@@ -0,0 +1,47 @@
1
+ import { HttpResponseError } from '@vultisig/lib-utils/fetch/HttpResponseError';
2
+ import { queryUrl } from '@vultisig/lib-utils/query/queryUrl';
3
+ import { normalizeMemberPool } from './memberPool.js';
4
+ import { thorchainMidgardBaseUrl } from './pools.js';
5
+ /**
6
+ * Fetch every LP position for a THORChain address in a single Midgard call.
7
+ *
8
+ * Returns an empty array when:
9
+ * - the address has no positions at all (Midgard returns 404), or
10
+ * - Midgard returns a body without a `pools` array (defensive).
11
+ *
12
+ * Prefer this over calling `getThorchainLpPosition` N times — one HTTP
13
+ * round-trip regardless of position count.
14
+ */
15
+ export const getThorchainLpPositions = async ({ thorAddress, }) => {
16
+ const url = `${thorchainMidgardBaseUrl}/v2/member/${encodeURIComponent(thorAddress)}`;
17
+ let raw;
18
+ try {
19
+ raw = await queryUrl(url);
20
+ }
21
+ catch (err) {
22
+ if (err instanceof HttpResponseError && err.status === 404)
23
+ return [];
24
+ throw err;
25
+ }
26
+ // Shape gates on the 200 response:
27
+ // - `raw` must be an object (not null, not a primitive, not an array of
28
+ // something unrelated) — otherwise the upstream shape is unrecognizable
29
+ // and we throw so the caller sees a real error.
30
+ // - `raw.pools` is allowed to be missing (treated as "no positions")
31
+ // for backward compat with the pre-404 era, when Midgard would
32
+ // return `{}` for known-empty addresses. A missing `pools` key is
33
+ // NOT treated as schema drift.
34
+ // - `raw.pools` MUST be an array if present — a non-array `pools`
35
+ // IS schema drift and we throw.
36
+ if (!raw || typeof raw !== 'object') {
37
+ throw new Error(`getThorchainLpPositions: unexpected Midgard response shape from ${url}`);
38
+ }
39
+ if (raw.pools === undefined) {
40
+ return [];
41
+ }
42
+ if (!Array.isArray(raw.pools)) {
43
+ throw new Error(`getThorchainLpPositions: Midgard response ${url} has non-array \`pools\` field`);
44
+ }
45
+ return raw.pools.map(normalizeMemberPool);
46
+ };
47
+ //# sourceMappingURL=positions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"positions.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/positions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAA;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAA;AAE7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA;AAGjD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,EAAE,EAC5C,WAAW,GAGZ,EAAkC,EAAE;IACnC,MAAM,GAAG,GAAG,GAAG,uBAAuB,cAAc,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAA;IACrF,IAAI,GAAsB,CAAA;IAC1B,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAoB,GAAG,CAAC,CAAA;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,iBAAiB,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,EAAE,CAAA;QACrE,MAAM,GAAG,CAAA;IACX,CAAC;IACD,mCAAmC;IACnC,0EAA0E;IAC1E,4EAA4E;IAC5E,oDAAoD;IACpD,uEAAuE;IACvE,mEAAmE;IACnE,sEAAsE;IACtE,mCAAmC;IACnC,oEAAoE;IACpE,oCAAoC;IACpC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,mEAAmE,GAAG,EAAE,CACzE,CAAA;IACH,CAAC;IACD,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAA;IACX,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,6CAA6C,GAAG,gCAAgC,CACjF,CAAA;IACH,CAAC;IACD,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;AAC3C,CAAC,CAAA"}
@@ -0,0 +1,45 @@
1
+ export type ThorchainLpPosition = {
2
+ pool: string;
3
+ liquidityUnits: string;
4
+ runeAdded: string;
5
+ assetAdded: string;
6
+ runePending: string;
7
+ assetPending: string;
8
+ runeAddress: string;
9
+ assetAddress: string;
10
+ /**
11
+ * Unix seconds of the last add. Midgard returns this; thornode does not,
12
+ * so positions sourced from the thornode fallback leave this as `"0"` and
13
+ * populate `lastAddHeight` instead.
14
+ */
15
+ dateLastAdded: string;
16
+ /**
17
+ * THORChain block height of the last add. Populated from thornode's
18
+ * `last_add_height` when the position comes from the thornode fallback
19
+ * path. Empty string when the position comes from Midgard (which does not
20
+ * expose block height on `/v2/member`). Either field is sufficient to gate
21
+ * the 1h lockup check — `dateLastAdded` via wall-clock window, or
22
+ * `lastAddHeight` via block-count window.
23
+ */
24
+ lastAddHeight: string;
25
+ /**
26
+ * True when either side has a non-zero pending amount. Common for
27
+ * asymmetric adds that THORChain has not yet credited.
28
+ */
29
+ isPending: boolean;
30
+ };
31
+ export type RawMemberPool = {
32
+ pool?: string;
33
+ liquidityUnits?: string;
34
+ runeAdded?: string;
35
+ assetAdded?: string;
36
+ runePending?: string;
37
+ assetPending?: string;
38
+ runeAddress?: string;
39
+ assetAddress?: string;
40
+ dateLastAdded?: string;
41
+ };
42
+ export type RawMemberResponse = {
43
+ pools?: RawMemberPool[];
44
+ };
45
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;;;;;;OAOG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,aAAa,EAAE,CAAA;CACxB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/types.ts"],"names":[],"mappings":""}
@@ -1,13 +1,38 @@
1
1
  /**
2
- * Verify a THORChain pool is currently depositable.
2
+ * Build the mimir flag key THORChain uses to pause LP deposits for a
3
+ * single pool. Format: `PAUSELPDEPOSIT-{CHAIN}-{ASSET_PLUS_CONTRACT}`.
3
4
  *
4
- * Hits the thornode `/thorchain/pool/{asset}` endpoint and asserts the
5
- * `status` field is `Available`. Throws on `Staged`, `Suspended`, or any
6
- * other non-Available state, and on network failures or unexpected payloads.
5
+ * Examples:
6
+ * BTC.BTC → PAUSELPDEPOSIT-BTC-BTC
7
+ * DOGE.DOGE → PAUSELPDEPOSIT-DOGE-DOGE
8
+ * ETH.USDC-0XA0B... → PAUSELPDEPOSIT-ETH-USDC-0XA0B...
7
9
  *
8
- * Use this as the fail-fast gate before building an LP add payload — it is
9
- * cheaper than building the payload first and discovering at broadcast time
10
- * that the pool is paused.
10
+ * Note: `CHAIN.ASSET` splits on the FIRST `.`; the rest (including any
11
+ * `-CONTRACT` suffix) is the asset portion, which is appended with a
12
+ * single `-` separator.
13
+ */
14
+ export declare const poolPauseMimirKey: (pool: string) => string;
15
+ /**
16
+ * Fetch the raw thornode mimir map. Returns an object with flag keys as
17
+ * numbers. Used to check per-pool LP deposit pauses (PAUSELPDEPOSIT-*),
18
+ * liquidity lockup (LIQUIDITYLOCKUPBLOCKS), etc.
19
+ */
20
+ export declare const getThorchainMimir: () => Promise<Record<string, number>>;
21
+ /**
22
+ * Verify a THORChain pool is currently depositable. Checks TWO layers:
23
+ *
24
+ * 1. **Thornode pool status** — `/thorchain/pool/{asset}.status` must be
25
+ * `Available`. Catches staged / suspended pools.
26
+ * 2. **Mimir per-pool pause flag** — `PAUSELPDEPOSIT-{chain}-{asset}`
27
+ * must not be set. Catches the case where the pool is listed as
28
+ * available BUT the THORChain handler rejects LP adds for it via
29
+ * mimir (what happened to BTC.BTC on 2026-04-10: pool.status was
30
+ * `Available`, deposits silently accepted into mempool, handler
31
+ * rejected at execution with "deposits are paused for asset
32
+ * (btc.btc): internal error"). Without the mimir check, the user
33
+ * signs a tx that is guaranteed to fail on-chain.
34
+ *
35
+ * Use this as the fail-fast gate before building an LP add payload.
11
36
  */
12
37
  export declare const assertPoolDepositable: (pool: string) => Promise<void>;
13
38
  //# sourceMappingURL=validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/validation.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,IAAI,CAetE,CAAA"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/cosmos/thor/lp/validation.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,MAQhD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsBxE,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,qBAAqB,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,IAAI,CAiCtE,CAAA"}