@andrewkimjoseph/celina-sdk 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -9
- package/build/abis/gooddollar-broker.d.ts +77 -0
- package/build/abis/gooddollar-broker.js +44 -0
- package/build/abis/gooddollar-broker.js.map +1 -0
- package/build/analytics/mcp-tool-events.js +3 -0
- package/build/analytics/mcp-tool-events.js.map +1 -1
- package/build/config/gooddollar.d.ts +12 -0
- package/build/config/gooddollar.js +19 -0
- package/build/config/gooddollar.js.map +1 -1
- package/build/index.d.ts +3 -2
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/services/ens.service.d.ts +1 -1
- package/build/services/ens.service.js +1 -1
- package/build/services/gooddollar.service.d.ts +57 -1
- package/build/services/gooddollar.service.js +256 -4
- package/build/services/gooddollar.service.js.map +1 -1
- package/build/services/transaction.service.d.ts +1 -1
- package/build/services/transaction.service.js +1 -1
- package/build/tools/domains/browser.js +3 -3
- package/build/tools/domains/browser.js.map +1 -1
- package/build/tools/domains/gooddollar.js +82 -1
- package/build/tools/domains/gooddollar.js.map +1 -1
- package/build/tools/schemas/common.d.ts +39 -0
- package/build/tools/schemas/common.js +11 -1
- package/build/tools/schemas/common.js.map +1 -1
- package/build/tools/swap-routing.d.ts +2 -2
- package/build/tools/swap-routing.js +68 -7
- package/build/tools/swap-routing.js.map +1 -1
- package/build/tools/types.d.ts +8 -0
- package/build/types/prepared.d.ts +1 -1
- package/package.json +1 -1
- package/tests/catalog/domains/defi.ts +179 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isGoodDollarUsdReservePair } from "../config/gooddollar.js";
|
|
1
2
|
function parseExpectedOut(value) {
|
|
2
3
|
const n = Number(value.replace(/,/g, ""));
|
|
3
4
|
return Number.isFinite(n) ? n : 0;
|
|
@@ -8,12 +9,31 @@ function isMentoRouteError(message) {
|
|
|
8
9
|
function isUniswapRouteError(message) {
|
|
9
10
|
return /no uniswap v4 route|insufficient liquidity in uniswap v4/i.test(message);
|
|
10
11
|
}
|
|
12
|
+
function isGoodDollarReserveRouteError(message) {
|
|
13
|
+
return /no gooddollar reserve route/i.test(message);
|
|
14
|
+
}
|
|
11
15
|
function isInsufficientBalanceError(message) {
|
|
12
16
|
return /insufficient .+ balance/i.test(message);
|
|
13
17
|
}
|
|
14
18
|
function rejectionMessage(reason) {
|
|
15
19
|
return reason instanceof Error ? reason.message : String(reason);
|
|
16
20
|
}
|
|
21
|
+
function filterAlternatives(best, others) {
|
|
22
|
+
if (best.protocol !== "gooddollar_reserve") {
|
|
23
|
+
return others;
|
|
24
|
+
}
|
|
25
|
+
const bestOut = parseExpectedOut(best.expectedOut);
|
|
26
|
+
if (bestOut <= 0) {
|
|
27
|
+
return others;
|
|
28
|
+
}
|
|
29
|
+
return others.filter((alt) => {
|
|
30
|
+
if (alt.protocol !== "uniswap_v4" || alt.error) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
const altOut = parseExpectedOut(alt.expectedOut);
|
|
34
|
+
return altOut >= bestOut * 0.95;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
17
37
|
async function tryMentoQuote(celina, tokenIn, tokenOut, amount, from) {
|
|
18
38
|
const quote = await celina.mentoFx.getFxQuote(tokenIn, tokenOut, amount, from);
|
|
19
39
|
return {
|
|
@@ -38,12 +58,32 @@ async function tryUniswapQuote(celina, tokenIn, tokenOut, amount, from) {
|
|
|
38
58
|
network: quote.network,
|
|
39
59
|
};
|
|
40
60
|
}
|
|
41
|
-
|
|
61
|
+
async function tryGoodDollarReserveQuote(celina, tokenIn, tokenOut, amount, from) {
|
|
62
|
+
const quote = await celina.gooddollar.getReserveQuote(tokenIn, tokenOut, amount, from);
|
|
63
|
+
return {
|
|
64
|
+
protocol: "gooddollar_reserve",
|
|
65
|
+
tokenIn: quote.tokenIn,
|
|
66
|
+
tokenOut: quote.tokenOut,
|
|
67
|
+
amountIn: quote.amountIn,
|
|
68
|
+
expectedOut: quote.expectedOut,
|
|
69
|
+
routeHops: quote.routeHops,
|
|
70
|
+
network: quote.network,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Quote a swap across Mento FX, GoodDollar reserve, and Uniswap v4; returns the best route. */
|
|
42
74
|
export async function getSwapQuoteWithFallback(celina, tokenIn, tokenOut, amount, from) {
|
|
43
|
-
const
|
|
75
|
+
const reserveEligible = isGoodDollarUsdReservePair(tokenIn, tokenOut);
|
|
76
|
+
const quoteTasks = [
|
|
44
77
|
tryMentoQuote(celina, tokenIn, tokenOut, amount, from),
|
|
45
78
|
tryUniswapQuote(celina, tokenIn, tokenOut, amount, from),
|
|
46
|
-
]
|
|
79
|
+
];
|
|
80
|
+
if (reserveEligible) {
|
|
81
|
+
quoteTasks.push(tryGoodDollarReserveQuote(celina, tokenIn, tokenOut, amount, from));
|
|
82
|
+
}
|
|
83
|
+
const results = await Promise.allSettled(quoteTasks);
|
|
84
|
+
const mentoResult = results[0];
|
|
85
|
+
const uniswapResult = results[1];
|
|
86
|
+
const reserveResult = reserveEligible ? results[2] : undefined;
|
|
47
87
|
const successes = [];
|
|
48
88
|
const alternatives = [];
|
|
49
89
|
if (mentoResult.status === "fulfilled") {
|
|
@@ -64,22 +104,37 @@ export async function getSwapQuoteWithFallback(celina, tokenIn, tokenOut, amount
|
|
|
64
104
|
alternatives.push({ protocol: "uniswap_v4", expectedOut: "0", error: message });
|
|
65
105
|
}
|
|
66
106
|
}
|
|
107
|
+
if (reserveResult) {
|
|
108
|
+
if (reserveResult.status === "fulfilled") {
|
|
109
|
+
successes.push(reserveResult.value);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const message = rejectionMessage(reserveResult.reason);
|
|
113
|
+
if (!isGoodDollarReserveRouteError(message)) {
|
|
114
|
+
alternatives.push({
|
|
115
|
+
protocol: "gooddollar_reserve",
|
|
116
|
+
expectedOut: "0",
|
|
117
|
+
error: message,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
67
122
|
if (successes.length === 0) {
|
|
68
|
-
const failures =
|
|
123
|
+
const failures = results
|
|
69
124
|
.filter((result) => result.status === "rejected")
|
|
70
125
|
.map((result) => rejectionMessage(result.reason));
|
|
71
126
|
const balanceError = failures.find(isInsufficientBalanceError);
|
|
72
127
|
if (balanceError) {
|
|
73
128
|
throw new Error(balanceError);
|
|
74
129
|
}
|
|
75
|
-
throw new Error(`No swap route for ${tokenIn} → ${tokenOut} via Mento FX or Uniswap v4.`);
|
|
130
|
+
throw new Error(`No swap route for ${tokenIn} → ${tokenOut} via Mento FX, GoodDollar reserve, or Uniswap v4.`);
|
|
76
131
|
}
|
|
77
132
|
successes.sort((a, b) => parseExpectedOut(b.expectedOut) - parseExpectedOut(a.expectedOut));
|
|
78
133
|
const best = successes[0];
|
|
79
|
-
const otherProtocols = successes.slice(1).map((q) => ({
|
|
134
|
+
const otherProtocols = filterAlternatives(best, successes.slice(1).map((q) => ({
|
|
80
135
|
protocol: q.protocol,
|
|
81
136
|
expectedOut: q.expectedOut,
|
|
82
|
-
}));
|
|
137
|
+
})));
|
|
83
138
|
return {
|
|
84
139
|
...best,
|
|
85
140
|
alternatives: otherProtocols.length > 0 ? otherProtocols : alternatives,
|
|
@@ -96,6 +151,12 @@ export async function prepareSwapWithFallback(celina, from, tokenIn, tokenOut, a
|
|
|
96
151
|
deadlineMinutes: params?.deadlineMinutes,
|
|
97
152
|
});
|
|
98
153
|
}
|
|
154
|
+
if (chosen === "gooddollar_reserve") {
|
|
155
|
+
return celina.gooddollar.prepareReserveSwap(from, tokenIn, tokenOut, amount, {
|
|
156
|
+
recipient: params?.recipient,
|
|
157
|
+
slippageTolerance: params?.slippageTolerance,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
99
160
|
return celina.uniswap.prepareSwap(from, tokenIn, tokenOut, amount, {
|
|
100
161
|
recipient: params?.recipient,
|
|
101
162
|
slippageTolerance: params?.slippageTolerance,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swap-routing.js","sourceRoot":"","sources":["../../src/tools/swap-routing.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"swap-routing.js","sourceRoot":"","sources":["../../src/tools/swap-routing.ts"],"names":[],"mappings":"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"}
|
package/build/tools/types.d.ts
CHANGED
|
@@ -83,6 +83,14 @@ export type CarbonWriteExecutors = {
|
|
|
83
83
|
};
|
|
84
84
|
export type GoodDollarWriteExecutors = {
|
|
85
85
|
claimDailyUbi: () => Promise<unknown>;
|
|
86
|
+
estimateReserveSwap: (tokenIn: string, tokenOut: string, amount: string, options?: {
|
|
87
|
+
recipient?: `0x${string}`;
|
|
88
|
+
slippageTolerance?: number;
|
|
89
|
+
}) => Promise<unknown>;
|
|
90
|
+
executeReserveSwap: (tokenIn: string, tokenOut: string, amount: string, options?: {
|
|
91
|
+
recipient?: `0x${string}`;
|
|
92
|
+
slippageTolerance?: number;
|
|
93
|
+
}) => Promise<unknown>;
|
|
86
94
|
};
|
|
87
95
|
export type SelfExecutors = {
|
|
88
96
|
verifyAgent: (args: Record<string, unknown>) => Promise<unknown>;
|
|
@@ -18,7 +18,7 @@ export interface PreparedFlow {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* JSON-safe prepared flow returned by prepare* tools and chat APIs.
|
|
21
|
-
* Consumers (celina-agent TxConfirmCard, wagmi) iterate steps and call sendTransaction.
|
|
21
|
+
* Consumers (celina-agent TxConfirmCard, wagmi) iterate steps and call sendTransactionAsync (wagmi) or walletClient.sendTransaction (viem).
|
|
22
22
|
*/
|
|
23
23
|
export interface SerializedPreparedFlow extends Omit<PreparedFlow, "steps"> {
|
|
24
24
|
steps: PreparedTx[];
|
package/package.json
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { OperationSpec } from "../types.js";
|
|
2
2
|
import { assertHasKeys } from "../../helpers/assert.js";
|
|
3
|
+
import { getSwapQuoteWithFallback } from "../../../src/tools/swap-routing.js";
|
|
4
|
+
import { GOODDOLLAR_MENTO_BROKER } from "../../../src/config/gooddollar.js";
|
|
3
5
|
|
|
4
6
|
function fromAddress(fx: Parameters<OperationSpec["assert"]>[1]): `0x${string}` {
|
|
5
7
|
return fx.signerAddress ?? fx.wallet;
|
|
@@ -310,4 +312,181 @@ export const gooddollarOperations: OperationSpec[] = [
|
|
|
310
312
|
assertHasKeys(result, ["hash"]);
|
|
311
313
|
},
|
|
312
314
|
},
|
|
315
|
+
{
|
|
316
|
+
id: "gooddollar.getReserveQuote.sell",
|
|
317
|
+
domain: "gooddollar",
|
|
318
|
+
layer: "read",
|
|
319
|
+
sdk: {
|
|
320
|
+
invoke: (client) =>
|
|
321
|
+
client.gooddollar.getReserveQuote("GoodDollar", "USDm", "1000"),
|
|
322
|
+
},
|
|
323
|
+
mcp: {
|
|
324
|
+
tool: "get_gooddollar_reserve_quote",
|
|
325
|
+
arguments: () => ({
|
|
326
|
+
token_in: "GoodDollar",
|
|
327
|
+
token_out: "USDm",
|
|
328
|
+
amount: "1000",
|
|
329
|
+
}),
|
|
330
|
+
},
|
|
331
|
+
assert: (result) => {
|
|
332
|
+
const quote = result as { protocol?: string; expectedOut?: string };
|
|
333
|
+
if (quote.protocol !== "gooddollar_reserve") {
|
|
334
|
+
throw new Error(`Expected gooddollar_reserve, got ${quote.protocol}`);
|
|
335
|
+
}
|
|
336
|
+
if (parseExpectedOut(quote.expectedOut) <= 0) {
|
|
337
|
+
throw new Error("Expected positive reserve output for G$ → USDm");
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
id: "gooddollar.getReserveQuote.buy",
|
|
343
|
+
domain: "gooddollar",
|
|
344
|
+
layer: "read",
|
|
345
|
+
sdk: {
|
|
346
|
+
invoke: (client) =>
|
|
347
|
+
client.gooddollar.getReserveQuote("USDm", "GoodDollar", "100"),
|
|
348
|
+
},
|
|
349
|
+
mcp: {
|
|
350
|
+
tool: "get_gooddollar_reserve_quote",
|
|
351
|
+
arguments: () => ({
|
|
352
|
+
token_in: "USDm",
|
|
353
|
+
token_out: "GoodDollar",
|
|
354
|
+
amount: "100",
|
|
355
|
+
}),
|
|
356
|
+
},
|
|
357
|
+
assert: (result) => {
|
|
358
|
+
const quote = result as { protocol?: string; expectedOut?: string };
|
|
359
|
+
if (quote.protocol !== "gooddollar_reserve") {
|
|
360
|
+
throw new Error(`Expected gooddollar_reserve, got ${quote.protocol}`);
|
|
361
|
+
}
|
|
362
|
+
if (parseExpectedOut(quote.expectedOut) <= 1000) {
|
|
363
|
+
throw new Error("Expected reserve to return substantially more G$ than Uniswap");
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
id: "swap.getSwapQuoteWithFallback.gdUsd",
|
|
369
|
+
domain: "swap",
|
|
370
|
+
layer: "read",
|
|
371
|
+
sdk: {
|
|
372
|
+
invoke: (client) =>
|
|
373
|
+
getSwapQuoteWithFallback(client, "GoodDollar", "USDm", "1000"),
|
|
374
|
+
},
|
|
375
|
+
assert: (result) => {
|
|
376
|
+
const quote = result as { protocol?: string };
|
|
377
|
+
if (quote.protocol !== "gooddollar_reserve") {
|
|
378
|
+
throw new Error(`Expected gooddollar_reserve, got ${quote.protocol}`);
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
id: "swap.getSwapQuoteWithFallback.usdGd",
|
|
384
|
+
domain: "swap",
|
|
385
|
+
layer: "read",
|
|
386
|
+
sdk: {
|
|
387
|
+
invoke: (client) =>
|
|
388
|
+
getSwapQuoteWithFallback(client, "USDm", "GoodDollar", "100"),
|
|
389
|
+
},
|
|
390
|
+
assert: (result) => {
|
|
391
|
+
const quote = result as { protocol?: string };
|
|
392
|
+
if (quote.protocol !== "gooddollar_reserve") {
|
|
393
|
+
throw new Error(`Expected gooddollar_reserve, got ${quote.protocol}`);
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
id: "gooddollar.prepareReserveSwap.sell",
|
|
399
|
+
domain: "gooddollar",
|
|
400
|
+
layer: "prepare",
|
|
401
|
+
requiresEnv: ["CELO_PRIVATE_KEY"],
|
|
402
|
+
sdk: {
|
|
403
|
+
invoke: (client, fx) =>
|
|
404
|
+
client.gooddollar.prepareReserveSwap(
|
|
405
|
+
fromAddress(fx),
|
|
406
|
+
"GoodDollar",
|
|
407
|
+
"USDm",
|
|
408
|
+
"1000",
|
|
409
|
+
),
|
|
410
|
+
},
|
|
411
|
+
assert: (result) => {
|
|
412
|
+
const flow = result as { steps?: Array<{ to?: string }> };
|
|
413
|
+
assertHasKeys(result, ["from", "steps"]);
|
|
414
|
+
const last = flow.steps?.at(-1);
|
|
415
|
+
if (last?.to?.toLowerCase() !== GOODDOLLAR_MENTO_BROKER.toLowerCase()) {
|
|
416
|
+
throw new Error("Expected final reserve swap step to target MentoBroker");
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
id: "gooddollar.prepareReserveSwap.buy",
|
|
422
|
+
domain: "gooddollar",
|
|
423
|
+
layer: "prepare",
|
|
424
|
+
requiresEnv: ["CELO_PRIVATE_KEY"],
|
|
425
|
+
sdk: {
|
|
426
|
+
invoke: (client, fx) =>
|
|
427
|
+
client.gooddollar.prepareReserveSwap(
|
|
428
|
+
fromAddress(fx),
|
|
429
|
+
"USDm",
|
|
430
|
+
"GoodDollar",
|
|
431
|
+
"10",
|
|
432
|
+
),
|
|
433
|
+
},
|
|
434
|
+
assert: (result) => {
|
|
435
|
+
const flow = result as { steps?: Array<{ to?: string }> };
|
|
436
|
+
assertHasKeys(result, ["from", "steps"]);
|
|
437
|
+
const last = flow.steps?.at(-1);
|
|
438
|
+
if (last?.to?.toLowerCase() !== GOODDOLLAR_MENTO_BROKER.toLowerCase()) {
|
|
439
|
+
throw new Error("Expected final reserve swap step to target MentoBroker");
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
id: "gooddollar.estimateReserveSwap.sell",
|
|
445
|
+
domain: "gooddollar",
|
|
446
|
+
layer: "read",
|
|
447
|
+
requiresEnv: ["CELO_PRIVATE_KEY"],
|
|
448
|
+
sdk: {
|
|
449
|
+
invoke: (client, fx) =>
|
|
450
|
+
client.gooddollar.estimateReserveSwap(
|
|
451
|
+
fromAddress(fx),
|
|
452
|
+
"GoodDollar",
|
|
453
|
+
"USDm",
|
|
454
|
+
"1000",
|
|
455
|
+
),
|
|
456
|
+
},
|
|
457
|
+
mcp: {
|
|
458
|
+
tool: "estimate_gooddollar_reserve_swap",
|
|
459
|
+
arguments: () => ({
|
|
460
|
+
token_in: "GoodDollar",
|
|
461
|
+
token_out: "USDm",
|
|
462
|
+
amount: "1000",
|
|
463
|
+
}),
|
|
464
|
+
},
|
|
465
|
+
assert: (result) => {
|
|
466
|
+
assertHasKeys(result, ["expectedOut", "approvalNeeded", "swapGas"]);
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
id: "gooddollar.executeReserveSwap.sell",
|
|
471
|
+
domain: "gooddollar",
|
|
472
|
+
layer: "write",
|
|
473
|
+
requiresEnv: ["CELO_PRIVATE_KEY"],
|
|
474
|
+
requiresWrites: true,
|
|
475
|
+
mcp: {
|
|
476
|
+
tool: "execute_gooddollar_reserve_swap",
|
|
477
|
+
arguments: () => ({
|
|
478
|
+
token_in: "GoodDollar",
|
|
479
|
+
token_out: "USDm",
|
|
480
|
+
amount: "1",
|
|
481
|
+
}),
|
|
482
|
+
},
|
|
483
|
+
assert: (result) => {
|
|
484
|
+
assertHasKeys(result, ["hash"]);
|
|
485
|
+
},
|
|
486
|
+
},
|
|
313
487
|
];
|
|
488
|
+
|
|
489
|
+
function parseExpectedOut(value: string | undefined): number {
|
|
490
|
+
const n = Number(String(value ?? "").replace(/,/g, ""));
|
|
491
|
+
return Number.isFinite(n) ? n : 0;
|
|
492
|
+
}
|