@kaleidorg/mind 0.10.6 → 0.10.7
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/dist/recipe/kaleidoswap-atomic.d.ts +13 -3
- package/dist/recipe/kaleidoswap-atomic.d.ts.map +1 -1
- package/dist/recipe/kaleidoswap-atomic.js +81 -40
- package/dist/recipe/kaleidoswap-atomic.js.map +1 -1
- package/package.json +1 -1
- package/skills/kaleido-trading/SKILL.md +4 -4
- package/src/funnel.mind.test.ts +2 -2
- package/src/recipe/kaleidoswap-atomic.test.ts +66 -5
- package/src/recipe/kaleidoswap-atomic.ts +101 -39
|
@@ -49,10 +49,20 @@ interface QuoteResult {
|
|
|
49
49
|
to_amount_display?: string;
|
|
50
50
|
fee_display?: string;
|
|
51
51
|
}
|
|
52
|
-
/** RLN
|
|
52
|
+
/** RLN's minimum HTLC for RGB payments when the node doesn't report one (rgb_htlc_min_msat). */
|
|
53
53
|
export declare const RLN_HTLC_MIN_MSAT = 3000000;
|
|
54
|
-
/**
|
|
55
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Why the node can't carry this swap over its Lightning channels, or null when
|
|
56
|
+
* it can (or the channel data doesn't say). RLN sends each leg as one HTLC and
|
|
57
|
+
* adds its RGB HTLC minimum to the BTC side and to the asset payment:
|
|
58
|
+
* - BTC → asset: BTC outbound ≥ amount + minimum; an asset channel with inbound
|
|
59
|
+
* ≥ the asset received and BTC inbound ≥ minimum.
|
|
60
|
+
* - asset → BTC: an asset channel holding the asset with BTC outbound ≥
|
|
61
|
+
* minimum; BTC inbound ≥ amount + minimum.
|
|
62
|
+
*/
|
|
63
|
+
export declare function swapLiquidityShortfall(q: QuoteResult | undefined, channels: unknown, htlcMinMsat?: number): string | null;
|
|
64
|
+
/** @deprecated Use `swapLiquidityShortfall`. */
|
|
65
|
+
export declare const outboundShortfall: typeof swapLiquidityShortfall;
|
|
56
66
|
export declare const kaleidoswapAtomicRecipe: Recipe;
|
|
57
67
|
export {};
|
|
58
68
|
//# sourceMappingURL=kaleidoswap-atomic.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kaleidoswap-atomic.d.ts","sourceRoot":"","sources":["../../src/recipe/kaleidoswap-atomic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,YAAY,CAAC;AAsCxD,UAAU,WAAW;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClG,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChG,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAOD,
|
|
1
|
+
{"version":3,"file":"kaleidoswap-atomic.d.ts","sourceRoot":"","sources":["../../src/recipe/kaleidoswap-atomic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,YAAY,CAAC;AAsCxD,UAAU,WAAW;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClG,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChG,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAOD,gGAAgG;AAChG,eAAO,MAAM,iBAAiB,UAAY,CAAC;AAwC3C;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,CAAC,EAAE,WAAW,GAAG,SAAS,EAC1B,QAAQ,EAAE,OAAO,EACjB,WAAW,GAAE,MAA0B,GACtC,MAAM,GAAG,IAAI,CAkDf;AAED,gDAAgD;AAChD,eAAO,MAAM,iBAAiB,+BAAyB,CAAC;AASxD,eAAO,MAAM,uBAAuB,EAAE,MAyHrC,CAAC"}
|
|
@@ -72,14 +72,13 @@ const SWAP_INTENT = (t) => {
|
|
|
72
72
|
// KaleidoSwap atomic is a BTC ↔ RGB venue: BTC settles on Lightning, RGB
|
|
73
73
|
// assets on RGB-over-Lightning. The maker/MCP layer is derived from the asset.
|
|
74
74
|
const layerFor = (asset) => /^btc$/i.test(String(asset)) ? 'BTC_LN' : 'RGB_LN';
|
|
75
|
-
/** RLN
|
|
75
|
+
/** RLN's minimum HTLC for RGB payments when the node doesn't report one (rgb_htlc_min_msat). */
|
|
76
76
|
export const RLN_HTLC_MIN_MSAT = 3_000_000;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function maxOutboundMsat(channels) {
|
|
77
|
+
const isBtc = (leg) => leg?.layer === 'BTC_LN' || (!leg?.layer && String(leg?.ticker ?? '').toUpperCase() === 'BTC');
|
|
78
|
+
const num = (v) => (v == null || v === '' || !Number.isFinite(Number(v)) ? undefined : Number(v));
|
|
79
|
+
const fmtSats = (msat) => `${Math.floor(msat / 1000).toLocaleString('en-US')} sats`;
|
|
80
|
+
const legText = (leg) => (leg?.amount_display ? `${leg.amount_display}${leg.ticker && !/sats?$/i.test(leg.amount_display) ? ` ${leg.ticker}` : ''}` : (leg?.ticker ?? 'the asset'));
|
|
81
|
+
function channelRows(channels) {
|
|
83
82
|
let list = channels;
|
|
84
83
|
if (typeof list === 'string') {
|
|
85
84
|
try {
|
|
@@ -90,40 +89,84 @@ function maxOutboundMsat(channels) {
|
|
|
90
89
|
}
|
|
91
90
|
}
|
|
92
91
|
const rows = Array.isArray(list) ? list : list?.channels;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (!rows.length)
|
|
98
|
-
return 0;
|
|
92
|
+
return Array.isArray(rows) ? rows : undefined;
|
|
93
|
+
}
|
|
94
|
+
/** Largest value of `pick` over usable channels; undefined when no channel reports it. */
|
|
95
|
+
function maxOver(rows, pick) {
|
|
99
96
|
let best;
|
|
100
97
|
let readable = false;
|
|
101
98
|
for (const c of rows) {
|
|
102
|
-
const
|
|
103
|
-
if (
|
|
99
|
+
const v = pick(c);
|
|
100
|
+
if (v === undefined)
|
|
104
101
|
continue;
|
|
105
102
|
readable = true;
|
|
106
103
|
if (c.is_usable === false || c.ready === false)
|
|
107
104
|
continue;
|
|
108
|
-
best = Math.max(best ?? 0,
|
|
105
|
+
best = Math.max(best ?? 0, v);
|
|
109
106
|
}
|
|
110
|
-
// Readable channels, none usable: nothing can send.
|
|
111
107
|
return best ?? (readable ? 0 : undefined);
|
|
112
108
|
}
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
109
|
+
const outbound = (c) => num(c.next_outbound_htlc_limit_msat ?? c.outbound_balance_msat);
|
|
110
|
+
const inbound = (c) => num(c.inbound_balance_msat);
|
|
111
|
+
/**
|
|
112
|
+
* Why the node can't carry this swap over its Lightning channels, or null when
|
|
113
|
+
* it can (or the channel data doesn't say). RLN sends each leg as one HTLC and
|
|
114
|
+
* adds its RGB HTLC minimum to the BTC side and to the asset payment:
|
|
115
|
+
* - BTC → asset: BTC outbound ≥ amount + minimum; an asset channel with inbound
|
|
116
|
+
* ≥ the asset received and BTC inbound ≥ minimum.
|
|
117
|
+
* - asset → BTC: an asset channel holding the asset with BTC outbound ≥
|
|
118
|
+
* minimum; BTC inbound ≥ amount + minimum.
|
|
119
|
+
*/
|
|
120
|
+
export function swapLiquidityShortfall(q, channels, htlcMinMsat = RLN_HTLC_MIN_MSAT) {
|
|
121
|
+
const from = q?.from_asset;
|
|
122
|
+
const to = q?.to_asset;
|
|
123
|
+
const fromBtc = isBtc(from);
|
|
124
|
+
const toBtc = isBtc(to);
|
|
125
|
+
if (fromBtc === toBtc)
|
|
119
126
|
return null;
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
127
|
+
const rows = channelRows(channels);
|
|
128
|
+
if (!rows)
|
|
122
129
|
return null;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
const min = fmtSats(htlcMinMsat);
|
|
131
|
+
if (!rows.length)
|
|
132
|
+
return `this swap runs over Lightning and you have no channels. Buy a channel first.`;
|
|
133
|
+
const usable = rows.filter((c) => c.is_usable !== false && c.ready !== false);
|
|
134
|
+
const hasAssetData = rows.some((c) => 'asset_id' in c);
|
|
135
|
+
if (fromBtc) {
|
|
136
|
+
const amount = num(from?.amount_raw);
|
|
137
|
+
const maxOut = maxOver(rows, outbound);
|
|
138
|
+
if (amount !== undefined && maxOut !== undefined && maxOut < amount + htlcMinMsat) {
|
|
139
|
+
const need = amount + htlcMinMsat;
|
|
140
|
+
return maxOut === 0
|
|
141
|
+
? `this swap needs a Lightning channel that can send ${fmtSats(need)} (the amount plus the ${min} HTLC minimum), and none can send right now. Buy a channel with at least that much outbound first.`
|
|
142
|
+
: `your channels can send at most ${fmtSats(maxOut)}, and this swap needs ${fmtSats(need)} (the amount plus the ${min} HTLC minimum). Swap at most ${fmtSats(Math.max(0, maxOut - htlcMinMsat))}, or buy a bigger channel.`;
|
|
143
|
+
}
|
|
144
|
+
const want = num(to?.amount_raw);
|
|
145
|
+
if (hasAssetData && want !== undefined) {
|
|
146
|
+
const ok = usable.some((c) => c.asset_id === to?.asset_id && (num(c.asset_remote_amount) ?? 0) >= want && (inbound(c) ?? Infinity) >= htlcMinMsat);
|
|
147
|
+
if (!ok) {
|
|
148
|
+
return `no channel can receive ${legText(to)}: you need a ${to?.ticker ?? 'asset'} channel with at least that much inbound and ${min} of BTC inbound. Buy an asset channel from the LSP first.`;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
// asset → BTC
|
|
154
|
+
const have = num(from?.amount_raw);
|
|
155
|
+
if (hasAssetData && have !== undefined) {
|
|
156
|
+
const ok = usable.some((c) => c.asset_id === from?.asset_id && (num(c.asset_local_amount) ?? 0) >= have && (outbound(c) ?? Infinity) >= htlcMinMsat);
|
|
157
|
+
if (!ok) {
|
|
158
|
+
return `no channel can send ${legText(from)}: you need a ${from?.ticker ?? 'asset'} channel holding at least that much, with ${min} of BTC outbound.`;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const amount = num(to?.amount_raw);
|
|
162
|
+
const maxIn = maxOver(rows, inbound);
|
|
163
|
+
if (amount !== undefined && maxIn !== undefined && maxIn < amount + htlcMinMsat) {
|
|
164
|
+
return `your channels can receive at most ${fmtSats(maxIn)}, and this swap pays you ${fmtSats(amount + htlcMinMsat)} (the amount plus the ${min} HTLC minimum). Swap for less BTC, or get more inbound.`;
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
126
167
|
}
|
|
168
|
+
/** @deprecated Use `swapLiquidityShortfall`. */
|
|
169
|
+
export const outboundShortfall = swapLiquidityShortfall;
|
|
127
170
|
// Render a quote leg as "<amount> <TICKER>" from the MCP quote echo, or undefined
|
|
128
171
|
// if the leg is missing (callers fall back to the user's slot values).
|
|
129
172
|
const quoteLeg = (leg) => leg?.amount_display != null ? `${leg.amount_display}${leg.ticker ? ` ${leg.ticker}` : ''}` : undefined;
|
|
@@ -167,17 +210,21 @@ export const kaleidoswapAtomicRecipe = {
|
|
|
167
210
|
: { ...base, from_amount: ctx.slots.amount };
|
|
168
211
|
},
|
|
169
212
|
},
|
|
170
|
-
// 1b. NODE:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
213
|
+
// 1b. NODE: pubkey for execute, and the node's RGB HTLC minimum.
|
|
214
|
+
{
|
|
215
|
+
tool: 'rln_get_node_info',
|
|
216
|
+
as: 'node',
|
|
217
|
+
args: () => ({}),
|
|
218
|
+
},
|
|
219
|
+
// 1c. NODE: can the channels carry both legs? RLN sends each leg as one
|
|
220
|
+
// HTLC and adds its HTLC minimum. Stop here, before the confirmation,
|
|
221
|
+
// instead of failing with NoRoute after the maker has locked the swap.
|
|
174
222
|
{
|
|
175
223
|
tool: 'rln_list_channels',
|
|
176
224
|
as: 'channels',
|
|
177
225
|
optional: true,
|
|
178
226
|
args: () => ({}),
|
|
179
|
-
|
|
180
|
-
check: (ctx) => outboundShortfall(ctx.results.quote, ctx.results.channels),
|
|
227
|
+
check: (ctx) => swapLiquidityShortfall(ctx.results.quote, ctx.results.channels, num(ctx.results.node?.rgb_htlc_min_msat) ?? RLN_HTLC_MIN_MSAT),
|
|
181
228
|
},
|
|
182
229
|
// 2. MAKER locks the swap. SwapRequest is flat (asset ids + maker-unit
|
|
183
230
|
// amounts) — sourced straight from the quote result, no re-scaling.
|
|
@@ -196,12 +243,6 @@ export const kaleidoswapAtomicRecipe = {
|
|
|
196
243
|
};
|
|
197
244
|
},
|
|
198
245
|
},
|
|
199
|
-
// 3. NODE: read our pubkey — the maker needs it as taker_pubkey for execute.
|
|
200
|
-
{
|
|
201
|
-
tool: 'rln_get_node_info',
|
|
202
|
-
as: 'node',
|
|
203
|
-
args: () => ({}),
|
|
204
|
-
},
|
|
205
246
|
// 4. NODE: the taker whitelists the maker's swapstring (accept the swap).
|
|
206
247
|
// Exposed by kaleido-mcp as `rln_atomic_taker` (calls rln.whitelistSwap).
|
|
207
248
|
// Ungated — covered by the single confirm above.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kaleidoswap-atomic.js","sourceRoot":"","sources":["../../src/recipe/kaleidoswap-atomic.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kaleidoswap-atomic.js","sourceRoot":"","sources":["../../src/recipe/kaleidoswap-atomic.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -17,10 +17,10 @@ ticker (`BTC`, `USDT`, `XAUT`) or an `rgb:…` id.
|
|
|
17
17
|
A swap runs over Lightning: it needs a channel with enough outbound in the
|
|
18
18
|
asset you send and enough inbound in the asset you receive. If
|
|
19
19
|
`rln_list_channels` shows none, buy one first (see `channel-manager`).
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
amount + 3,000
|
|
23
|
-
or a bigger channel.
|
|
20
|
+
Each leg is one payment plus the node's 3,000-sat HTLC minimum: sending BTC
|
|
21
|
+
needs one channel with outbound ≥ amount + 3,000 sats, receiving BTC inbound ≥
|
|
22
|
+
amount + 3,000; the asset side needs an asset channel holding the asset (or
|
|
23
|
+
inbound for it). Short: offer a smaller swap or a bigger channel.
|
|
24
24
|
|
|
25
25
|
## Do
|
|
26
26
|
- Quote with exactly one amount: `from_amount` to sell a fixed input,
|
package/src/funnel.mind.test.ts
CHANGED
|
@@ -212,9 +212,9 @@ describe('desktop mind — buy assets via atomic swap', () => {
|
|
|
212
212
|
// The full deterministic chain, in order.
|
|
213
213
|
expect(calls.map((c) => c.name)).toEqual([
|
|
214
214
|
'kaleidoswap_get_quote',
|
|
215
|
+
'rln_get_node_info',
|
|
215
216
|
'rln_list_channels',
|
|
216
217
|
'kaleidoswap_atomic_init',
|
|
217
|
-
'rln_get_node_info',
|
|
218
218
|
'rln_atomic_taker',
|
|
219
219
|
'kaleidoswap_atomic_execute',
|
|
220
220
|
]);
|
|
@@ -257,9 +257,9 @@ describe('desktop mind — buy assets via atomic swap', () => {
|
|
|
257
257
|
expect(res.route).toBe('kaleidoswap-atomic');
|
|
258
258
|
expect(calls.map((c) => c.name)).toEqual([
|
|
259
259
|
'kaleidoswap_get_quote',
|
|
260
|
+
'rln_get_node_info',
|
|
260
261
|
'rln_list_channels',
|
|
261
262
|
'kaleidoswap_atomic_init',
|
|
262
|
-
'rln_get_node_info',
|
|
263
263
|
'rln_atomic_taker',
|
|
264
264
|
'kaleidoswap_atomic_execute',
|
|
265
265
|
]);
|
|
@@ -204,8 +204,8 @@ describe('kaleidoswapAtomicRecipe — full chain', () => {
|
|
|
204
204
|
expect(res.inferences).toBe(0);
|
|
205
205
|
expect(captured.map((c) => c.name)).toEqual([
|
|
206
206
|
'kaleidoswap_get_quote',
|
|
207
|
-
'kaleidoswap_atomic_init',
|
|
208
207
|
'rln_get_node_info',
|
|
208
|
+
'kaleidoswap_atomic_init',
|
|
209
209
|
'rln_atomic_taker',
|
|
210
210
|
'kaleidoswap_atomic_execute',
|
|
211
211
|
]);
|
|
@@ -307,7 +307,68 @@ describe('kaleidoswapAtomicRecipe — single confirmation', () => {
|
|
|
307
307
|
|
|
308
308
|
expect(res.status).toBe('cancelled');
|
|
309
309
|
// Quote ran (read-only), but NOTHING after the declined gate.
|
|
310
|
-
expect(captured.map((c) => c.name)).toEqual(['kaleidoswap_get_quote']);
|
|
310
|
+
expect(captured.map((c) => c.name)).toEqual(['kaleidoswap_get_quote', 'rln_get_node_info']);
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
describe('kaleidoswapAtomicRecipe — channel liquidity preflight', () => {
|
|
315
|
+
const btcToUsdt = {
|
|
316
|
+
rfq_id: 'rfq-2',
|
|
317
|
+
from_asset: { asset_id: 'BTC', ticker: 'BTC', layer: 'BTC_LN', amount_raw: 50_000_000, amount_display: '50,000 sats' },
|
|
318
|
+
to_asset: { asset_id: 'rgb:usdt', ticker: 'USDT', layer: 'RGB_LN', amount_raw: 30_000_000, amount_display: '30' },
|
|
319
|
+
};
|
|
320
|
+
const usdtToBtc = {
|
|
321
|
+
rfq_id: 'rfq-3',
|
|
322
|
+
from_asset: { asset_id: 'rgb:usdt', ticker: 'USDT', layer: 'RGB_LN', amount_raw: 10_000_000, amount_display: '10' },
|
|
323
|
+
to_asset: { asset_id: 'BTC', ticker: 'BTC', layer: 'BTC_LN', amount_raw: 15_000_000, amount_display: '15,000 sats' },
|
|
324
|
+
};
|
|
325
|
+
const usdtChannel = (over: Record<string, unknown> = {}) => ({
|
|
326
|
+
ready: true,
|
|
327
|
+
is_usable: true,
|
|
328
|
+
asset_id: 'rgb:usdt',
|
|
329
|
+
asset_local_amount: 20_000_000,
|
|
330
|
+
asset_remote_amount: 40_000_000,
|
|
331
|
+
next_outbound_htlc_limit_msat: 60_000_000,
|
|
332
|
+
inbound_balance_msat: 50_000_000,
|
|
333
|
+
...over,
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('BTC -> asset: BTC outbound must cover the amount plus the HTLC minimum', async () => {
|
|
337
|
+
const { swapLiquidityShortfall } = await import('./kaleidoswap-atomic.js');
|
|
338
|
+
expect(swapLiquidityShortfall(btcToUsdt as never, { channels: [usdtChannel({ next_outbound_htlc_limit_msat: 51_000_000 })] })).toBe(
|
|
339
|
+
'your channels can send at most 51,000 sats, and this swap needs 53,000 sats (the amount plus the 3,000 sats HTLC minimum). Swap at most 48,000 sats, or buy a bigger channel.',
|
|
340
|
+
);
|
|
341
|
+
expect(swapLiquidityShortfall(btcToUsdt as never, { channels: [usdtChannel()] })).toBeNull();
|
|
342
|
+
expect(swapLiquidityShortfall(btcToUsdt as never, { channels: [] })).toMatch(/no channels/);
|
|
343
|
+
expect(swapLiquidityShortfall(btcToUsdt as never, { channels: [usdtChannel({ ready: false })] })).toMatch(/none can send right now/);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('BTC -> asset: an asset channel must be able to receive the asset', async () => {
|
|
347
|
+
const { swapLiquidityShortfall } = await import('./kaleidoswap-atomic.js');
|
|
348
|
+
expect(swapLiquidityShortfall(btcToUsdt as never, { channels: [usdtChannel({ asset_remote_amount: 5_000_000 })] })).toMatch(
|
|
349
|
+
/^no channel can receive 30 USDT/,
|
|
350
|
+
);
|
|
351
|
+
expect(swapLiquidityShortfall(btcToUsdt as never, { channels: [usdtChannel({ inbound_balance_msat: 1_000_000 })] })).toMatch(
|
|
352
|
+
/^no channel can receive 30 USDT/,
|
|
353
|
+
);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('asset -> BTC: the asset must be on our side and BTC inbound must cover amount + minimum', async () => {
|
|
357
|
+
const { swapLiquidityShortfall } = await import('./kaleidoswap-atomic.js');
|
|
358
|
+
expect(swapLiquidityShortfall(usdtToBtc as never, { channels: [usdtChannel()] })).toBeNull();
|
|
359
|
+
expect(swapLiquidityShortfall(usdtToBtc as never, { channels: [usdtChannel({ asset_local_amount: 1_000_000 })] })).toMatch(
|
|
360
|
+
/^no channel can send 10 USDT/,
|
|
361
|
+
);
|
|
362
|
+
expect(swapLiquidityShortfall(usdtToBtc as never, { channels: [usdtChannel({ inbound_balance_msat: 10_000_000 })] })).toBe(
|
|
363
|
+
'your channels can receive at most 10,000 sats, and this swap pays you 18,000 sats (the amount plus the 3,000 sats HTLC minimum). Swap for less BTC, or get more inbound.',
|
|
364
|
+
);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it("uses the node's HTLC minimum and doesn't block on unreadable data", async () => {
|
|
368
|
+
const { swapLiquidityShortfall } = await import('./kaleidoswap-atomic.js');
|
|
369
|
+
expect(swapLiquidityShortfall(btcToUsdt as never, { channels: [usdtChannel({ next_outbound_htlc_limit_msat: 51_000_000 })] }, 1_000_000)).toBeNull();
|
|
370
|
+
expect(swapLiquidityShortfall(btcToUsdt as never, { channels: [{ channel_id: 'x' }] })).toBeNull();
|
|
371
|
+
expect(swapLiquidityShortfall(btcToUsdt as never, 'not json')).toBeNull();
|
|
311
372
|
});
|
|
312
373
|
});
|
|
313
374
|
|
|
@@ -321,10 +382,10 @@ describe('kaleidoswapAtomicRecipe — outbound preflight (BTC leg + RLN HTLC min
|
|
|
321
382
|
it('reports the shortfall in plain numbers', async () => {
|
|
322
383
|
const { outboundShortfall } = await import('./kaleidoswap-atomic.js');
|
|
323
384
|
expect(outboundShortfall(btcQuote as never, { channels: [{ ready: true, is_usable: true, outbound_balance_msat: 51_000_000 }] })).toBe(
|
|
324
|
-
'your channels can send at most 51,000 sats, and this swap needs 53,000 sats (the amount plus
|
|
385
|
+
'your channels can send at most 51,000 sats, and this swap needs 53,000 sats (the amount plus the 3,000 sats HTLC minimum). Swap at most 48,000 sats, or buy a bigger channel.',
|
|
325
386
|
);
|
|
326
387
|
expect(outboundShortfall(btcQuote as never, { channels: [{ ready: true, next_outbound_htlc_limit_msat: 60_000_000 }] })).toBeNull();
|
|
327
|
-
expect(outboundShortfall(btcQuote as never, { channels: [] })).toMatch(/
|
|
388
|
+
expect(outboundShortfall(btcQuote as never, { channels: [] })).toMatch(/no channels/);
|
|
328
389
|
expect(outboundShortfall(btcQuote as never, { something: 'else' })).toBeNull();
|
|
329
390
|
expect(outboundShortfall(btcQuote as never, { channels: [{ ready: false, outbound_balance_msat: 900_000_000 }] })).toMatch(/none can send right now/);
|
|
330
391
|
expect(outboundShortfall(btcQuote as never, { channels: [{ channel_id: 'x' }] })).toBeNull();
|
|
@@ -367,7 +428,7 @@ describe('kaleidoswapAtomicRecipe — outbound preflight (BTC leg + RLN HTLC min
|
|
|
367
428
|
});
|
|
368
429
|
expect(res.status).toBe('error');
|
|
369
430
|
expect(res.text).toMatch(/can send at most 3,000 sats.*needs 53,000 sats/);
|
|
370
|
-
expect(calls).toEqual(['kaleidoswap_get_quote', 'rln_list_channels']);
|
|
431
|
+
expect(calls).toEqual(['kaleidoswap_get_quote', 'rln_get_node_info', 'rln_list_channels']);
|
|
371
432
|
expect(confirms).toEqual([]);
|
|
372
433
|
});
|
|
373
434
|
});
|
|
@@ -85,16 +85,18 @@ interface QuoteResult {
|
|
|
85
85
|
const layerFor = (asset: unknown): string =>
|
|
86
86
|
/^btc$/i.test(String(asset)) ? 'BTC_LN' : 'RGB_LN';
|
|
87
87
|
|
|
88
|
-
/** RLN
|
|
88
|
+
/** RLN's minimum HTLC for RGB payments when the node doesn't report one (rgb_htlc_min_msat). */
|
|
89
89
|
export const RLN_HTLC_MIN_MSAT = 3_000_000;
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
type Leg = { asset_id?: string; ticker?: string; layer?: string; amount_raw?: number; amount_display?: string };
|
|
92
|
+
type Channel = Record<string, unknown>;
|
|
93
|
+
|
|
94
|
+
const isBtc = (leg?: Leg) => leg?.layer === 'BTC_LN' || (!leg?.layer && String(leg?.ticker ?? '').toUpperCase() === 'BTC');
|
|
95
|
+
const num = (v: unknown): number | undefined => (v == null || v === '' || !Number.isFinite(Number(v)) ? undefined : Number(v));
|
|
96
|
+
const fmtSats = (msat: number) => `${Math.floor(msat / 1000).toLocaleString('en-US')} sats`;
|
|
97
|
+
const legText = (leg?: Leg) => (leg?.amount_display ? `${leg.amount_display}${leg.ticker && !/sats?$/i.test(leg.amount_display) ? ` ${leg.ticker}` : ''}` : (leg?.ticker ?? 'the asset'));
|
|
95
98
|
|
|
96
|
-
|
|
97
|
-
function maxOutboundMsat(channels: unknown): number | undefined {
|
|
99
|
+
function channelRows(channels: unknown): Channel[] | undefined {
|
|
98
100
|
let list: unknown = channels;
|
|
99
101
|
if (typeof list === 'string') {
|
|
100
102
|
try {
|
|
@@ -104,37 +106,94 @@ function maxOutboundMsat(channels: unknown): number | undefined {
|
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
const rows = Array.isArray(list) ? list : (list as { channels?: unknown })?.channels;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
return Array.isArray(rows) ? (rows as Channel[]) : undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Largest value of `pick` over usable channels; undefined when no channel reports it. */
|
|
113
|
+
function maxOver(rows: Channel[], pick: (c: Channel) => number | undefined): number | undefined {
|
|
111
114
|
let best: number | undefined;
|
|
112
115
|
let readable = false;
|
|
113
|
-
for (const c of rows
|
|
114
|
-
const
|
|
115
|
-
if (
|
|
116
|
+
for (const c of rows) {
|
|
117
|
+
const v = pick(c);
|
|
118
|
+
if (v === undefined) continue;
|
|
116
119
|
readable = true;
|
|
117
120
|
if (c.is_usable === false || c.ready === false) continue;
|
|
118
|
-
best = Math.max(best ?? 0,
|
|
121
|
+
best = Math.max(best ?? 0, v);
|
|
119
122
|
}
|
|
120
|
-
// Readable channels, none usable: nothing can send.
|
|
121
123
|
return best ?? (readable ? 0 : undefined);
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
const
|
|
126
|
+
const outbound = (c: Channel) => num(c.next_outbound_htlc_limit_msat ?? c.outbound_balance_msat);
|
|
127
|
+
const inbound = (c: Channel) => num(c.inbound_balance_msat);
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Why the node can't carry this swap over its Lightning channels, or null when
|
|
131
|
+
* it can (or the channel data doesn't say). RLN sends each leg as one HTLC and
|
|
132
|
+
* adds its RGB HTLC minimum to the BTC side and to the asset payment:
|
|
133
|
+
* - BTC → asset: BTC outbound ≥ amount + minimum; an asset channel with inbound
|
|
134
|
+
* ≥ the asset received and BTC inbound ≥ minimum.
|
|
135
|
+
* - asset → BTC: an asset channel holding the asset with BTC outbound ≥
|
|
136
|
+
* minimum; BTC inbound ≥ amount + minimum.
|
|
137
|
+
*/
|
|
138
|
+
export function swapLiquidityShortfall(
|
|
139
|
+
q: QuoteResult | undefined,
|
|
140
|
+
channels: unknown,
|
|
141
|
+
htlcMinMsat: number = RLN_HTLC_MIN_MSAT,
|
|
142
|
+
): string | null {
|
|
143
|
+
const from = q?.from_asset as Leg | undefined;
|
|
144
|
+
const to = q?.to_asset as Leg | undefined;
|
|
145
|
+
const fromBtc = isBtc(from);
|
|
146
|
+
const toBtc = isBtc(to);
|
|
147
|
+
if (fromBtc === toBtc) return null;
|
|
148
|
+
const rows = channelRows(channels);
|
|
149
|
+
if (!rows) return null;
|
|
150
|
+
const min = fmtSats(htlcMinMsat);
|
|
151
|
+
if (!rows.length) return `this swap runs over Lightning and you have no channels. Buy a channel first.`;
|
|
152
|
+
const usable = rows.filter((c) => c.is_usable !== false && c.ready !== false);
|
|
153
|
+
const hasAssetData = rows.some((c) => 'asset_id' in c);
|
|
125
154
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
155
|
+
if (fromBtc) {
|
|
156
|
+
const amount = num(from?.amount_raw);
|
|
157
|
+
const maxOut = maxOver(rows, outbound);
|
|
158
|
+
if (amount !== undefined && maxOut !== undefined && maxOut < amount + htlcMinMsat) {
|
|
159
|
+
const need = amount + htlcMinMsat;
|
|
160
|
+
return maxOut === 0
|
|
161
|
+
? `this swap needs a Lightning channel that can send ${fmtSats(need)} (the amount plus the ${min} HTLC minimum), and none can send right now. Buy a channel with at least that much outbound first.`
|
|
162
|
+
: `your channels can send at most ${fmtSats(maxOut)}, and this swap needs ${fmtSats(need)} (the amount plus the ${min} HTLC minimum). Swap at most ${fmtSats(Math.max(0, maxOut - htlcMinMsat))}, or buy a bigger channel.`;
|
|
163
|
+
}
|
|
164
|
+
const want = num(to?.amount_raw);
|
|
165
|
+
if (hasAssetData && want !== undefined) {
|
|
166
|
+
const ok = usable.some(
|
|
167
|
+
(c) => c.asset_id === to?.asset_id && (num(c.asset_remote_amount) ?? 0) >= want && (inbound(c) ?? Infinity) >= htlcMinMsat,
|
|
168
|
+
);
|
|
169
|
+
if (!ok) {
|
|
170
|
+
return `no channel can receive ${legText(to)}: you need a ${to?.ticker ?? 'asset'} channel with at least that much inbound and ${min} of BTC inbound. Buy an asset channel from the LSP first.`;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// asset → BTC
|
|
177
|
+
const have = num(from?.amount_raw);
|
|
178
|
+
if (hasAssetData && have !== undefined) {
|
|
179
|
+
const ok = usable.some(
|
|
180
|
+
(c) => c.asset_id === from?.asset_id && (num(c.asset_local_amount) ?? 0) >= have && (outbound(c) ?? Infinity) >= htlcMinMsat,
|
|
181
|
+
);
|
|
182
|
+
if (!ok) {
|
|
183
|
+
return `no channel can send ${legText(from)}: you need a ${from?.ticker ?? 'asset'} channel holding at least that much, with ${min} of BTC outbound.`;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const amount = num(to?.amount_raw);
|
|
187
|
+
const maxIn = maxOver(rows, inbound);
|
|
188
|
+
if (amount !== undefined && maxIn !== undefined && maxIn < amount + htlcMinMsat) {
|
|
189
|
+
return `your channels can receive at most ${fmtSats(maxIn)}, and this swap pays you ${fmtSats(amount + htlcMinMsat)} (the amount plus the ${min} HTLC minimum). Swap for less BTC, or get more inbound.`;
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
136
192
|
}
|
|
137
193
|
|
|
194
|
+
/** @deprecated Use `swapLiquidityShortfall`. */
|
|
195
|
+
export const outboundShortfall = swapLiquidityShortfall;
|
|
196
|
+
|
|
138
197
|
// Render a quote leg as "<amount> <TICKER>" from the MCP quote echo, or undefined
|
|
139
198
|
// if the leg is missing (callers fall back to the user's slot values).
|
|
140
199
|
const quoteLeg = (leg?: { ticker?: string; amount_display?: string }): string | undefined =>
|
|
@@ -183,17 +242,26 @@ export const kaleidoswapAtomicRecipe: Recipe = {
|
|
|
183
242
|
: { ...base, from_amount: ctx.slots.amount };
|
|
184
243
|
},
|
|
185
244
|
},
|
|
186
|
-
// 1b. NODE:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
245
|
+
// 1b. NODE: pubkey for execute, and the node's RGB HTLC minimum.
|
|
246
|
+
{
|
|
247
|
+
tool: 'rln_get_node_info',
|
|
248
|
+
as: 'node',
|
|
249
|
+
args: () => ({}),
|
|
250
|
+
},
|
|
251
|
+
// 1c. NODE: can the channels carry both legs? RLN sends each leg as one
|
|
252
|
+
// HTLC and adds its HTLC minimum. Stop here, before the confirmation,
|
|
253
|
+
// instead of failing with NoRoute after the maker has locked the swap.
|
|
190
254
|
{
|
|
191
255
|
tool: 'rln_list_channels',
|
|
192
256
|
as: 'channels',
|
|
193
257
|
optional: true,
|
|
194
258
|
args: () => ({}),
|
|
195
|
-
|
|
196
|
-
|
|
259
|
+
check: (ctx) =>
|
|
260
|
+
swapLiquidityShortfall(
|
|
261
|
+
ctx.results.quote as QuoteResult | undefined,
|
|
262
|
+
ctx.results.channels,
|
|
263
|
+
num((ctx.results.node as { rgb_htlc_min_msat?: unknown } | undefined)?.rgb_htlc_min_msat) ?? RLN_HTLC_MIN_MSAT,
|
|
264
|
+
),
|
|
197
265
|
},
|
|
198
266
|
// 2. MAKER locks the swap. SwapRequest is flat (asset ids + maker-unit
|
|
199
267
|
// amounts) — sourced straight from the quote result, no re-scaling.
|
|
@@ -212,12 +280,6 @@ export const kaleidoswapAtomicRecipe: Recipe = {
|
|
|
212
280
|
};
|
|
213
281
|
},
|
|
214
282
|
},
|
|
215
|
-
// 3. NODE: read our pubkey — the maker needs it as taker_pubkey for execute.
|
|
216
|
-
{
|
|
217
|
-
tool: 'rln_get_node_info',
|
|
218
|
-
as: 'node',
|
|
219
|
-
args: () => ({}),
|
|
220
|
-
},
|
|
221
283
|
// 4. NODE: the taker whitelists the maker's swapstring (accept the swap).
|
|
222
284
|
// Exposed by kaleido-mcp as `rln_atomic_taker` (calls rln.whitelistSwap).
|
|
223
285
|
// Ungated — covered by the single confirm above.
|