@tabai/sdk 0.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.
- package/LICENSE +23 -0
- package/README.md +401 -0
- package/bin/tab.mjs +23 -0
- package/dist/_shared/abi.d.ts +150 -0
- package/dist/_shared/abi.d.ts.map +1 -0
- package/dist/_shared/abi.js +197 -0
- package/dist/_shared/abi.js.map +1 -0
- package/dist/_shared/chains.d.ts +118 -0
- package/dist/_shared/chains.d.ts.map +1 -0
- package/dist/_shared/chains.js +89 -0
- package/dist/_shared/chains.js.map +1 -0
- package/dist/_shared/hex.d.ts +35 -0
- package/dist/_shared/hex.d.ts.map +1 -0
- package/dist/_shared/hex.js +40 -0
- package/dist/_shared/hex.js.map +1 -0
- package/dist/_shared/index.d.ts +14 -0
- package/dist/_shared/index.d.ts.map +1 -0
- package/dist/_shared/index.js +14 -0
- package/dist/_shared/index.js.map +1 -0
- package/dist/_shared/keccak256.d.ts +29 -0
- package/dist/_shared/keccak256.d.ts.map +1 -0
- package/dist/_shared/keccak256.js +145 -0
- package/dist/_shared/keccak256.js.map +1 -0
- package/dist/_shared/result.d.ts +78 -0
- package/dist/_shared/result.d.ts.map +1 -0
- package/dist/_shared/result.js +61 -0
- package/dist/_shared/result.js.map +1 -0
- package/dist/cli/client-config.d.ts +155 -0
- package/dist/cli/client-config.d.ts.map +1 -0
- package/dist/cli/client-config.js +382 -0
- package/dist/cli/client-config.js.map +1 -0
- package/dist/cli/connect.d.ts +76 -0
- package/dist/cli/connect.d.ts.map +1 -0
- package/dist/cli/connect.js +158 -0
- package/dist/cli/connect.js.map +1 -0
- package/dist/cli/doctor.d.ts +57 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +253 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +13 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/main.d.ts +45 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +371 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +37 -0
- package/dist/errors.js.map +1 -0
- package/dist/http/client-402.d.ts +243 -0
- package/dist/http/client-402.d.ts.map +1 -0
- package/dist/http/client-402.js +515 -0
- package/dist/http/client-402.js.map +1 -0
- package/dist/http/headers.d.ts +173 -0
- package/dist/http/headers.d.ts.map +1 -0
- package/dist/http/headers.js +284 -0
- package/dist/http/headers.js.map +1 -0
- package/dist/http/index.d.ts +15 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +15 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/metering-claim.d.ts +82 -0
- package/dist/http/metering-claim.d.ts.map +1 -0
- package/dist/http/metering-claim.js +99 -0
- package/dist/http/metering-claim.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +40 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +50 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/assets.d.ts +31 -0
- package/dist/mcp/assets.d.ts.map +1 -0
- package/dist/mcp/assets.js +78 -0
- package/dist/mcp/assets.js.map +1 -0
- package/dist/mcp/index.d.ts +19 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +19 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/json-schema.d.ts +86 -0
- package/dist/mcp/json-schema.d.ts.map +1 -0
- package/dist/mcp/json-schema.js +215 -0
- package/dist/mcp/json-schema.js.map +1 -0
- package/dist/mcp/json.d.ts +43 -0
- package/dist/mcp/json.d.ts.map +1 -0
- package/dist/mcp/json.js +69 -0
- package/dist/mcp/json.js.map +1 -0
- package/dist/mcp/registry-client.d.ts +88 -0
- package/dist/mcp/registry-client.d.ts.map +1 -0
- package/dist/mcp/registry-client.js +158 -0
- package/dist/mcp/registry-client.js.map +1 -0
- package/dist/mcp/schemas.d.ts +82 -0
- package/dist/mcp/schemas.d.ts.map +1 -0
- package/dist/mcp/schemas.js +493 -0
- package/dist/mcp/schemas.js.map +1 -0
- package/dist/mcp/server.d.ts +97 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +285 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/settings.d.ts +90 -0
- package/dist/mcp/settings.d.ts.map +1 -0
- package/dist/mcp/settings.js +160 -0
- package/dist/mcp/settings.js.map +1 -0
- package/dist/mcp/toolset.d.ts +231 -0
- package/dist/mcp/toolset.d.ts.map +1 -0
- package/dist/mcp/toolset.js +760 -0
- package/dist/mcp/toolset.js.map +1 -0
- package/dist/payments/abi.d.ts +9 -0
- package/dist/payments/abi.d.ts.map +1 -0
- package/dist/payments/abi.js +17 -0
- package/dist/payments/abi.js.map +1 -0
- package/dist/payments/config.d.ts +199 -0
- package/dist/payments/config.d.ts.map +1 -0
- package/dist/payments/config.js +259 -0
- package/dist/payments/config.js.map +1 -0
- package/dist/payments/index.d.ts +13 -0
- package/dist/payments/index.d.ts.map +1 -0
- package/dist/payments/index.js +13 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/payments/kuru.d.ts +191 -0
- package/dist/payments/kuru.d.ts.map +1 -0
- package/dist/payments/kuru.js +377 -0
- package/dist/payments/kuru.js.map +1 -0
- package/dist/payments/monad.d.ts +69 -0
- package/dist/payments/monad.d.ts.map +1 -0
- package/dist/payments/monad.js +306 -0
- package/dist/payments/monad.js.map +1 -0
- package/dist/payments/permit2.d.ts +118 -0
- package/dist/payments/permit2.d.ts.map +1 -0
- package/dist/payments/permit2.js +366 -0
- package/dist/payments/permit2.js.map +1 -0
- package/dist/payments/registry.d.ts +119 -0
- package/dist/payments/registry.d.ts.map +1 -0
- package/dist/payments/registry.js +199 -0
- package/dist/payments/registry.js.map +1 -0
- package/dist/payments/strategy.d.ts +80 -0
- package/dist/payments/strategy.d.ts.map +1 -0
- package/dist/payments/strategy.js +103 -0
- package/dist/payments/strategy.js.map +1 -0
- package/dist/proxy/hooks.d.ts +90 -0
- package/dist/proxy/hooks.d.ts.map +1 -0
- package/dist/proxy/hooks.js +35 -0
- package/dist/proxy/hooks.js.map +1 -0
- package/dist/proxy/index.d.ts +9 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +9 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/proxy/proxy.d.ts +156 -0
- package/dist/proxy/proxy.d.ts.map +1 -0
- package/dist/proxy/proxy.js +366 -0
- package/dist/proxy/proxy.js.map +1 -0
- package/dist/server/adapters/express.d.ts +89 -0
- package/dist/server/adapters/express.d.ts.map +1 -0
- package/dist/server/adapters/express.js +215 -0
- package/dist/server/adapters/express.js.map +1 -0
- package/dist/server/adapters/hono.d.ts +52 -0
- package/dist/server/adapters/hono.d.ts.map +1 -0
- package/dist/server/adapters/hono.js +61 -0
- package/dist/server/adapters/hono.js.map +1 -0
- package/dist/server/adapters/next.d.ts +52 -0
- package/dist/server/adapters/next.d.ts.map +1 -0
- package/dist/server/adapters/next.js +56 -0
- package/dist/server/adapters/next.js.map +1 -0
- package/dist/server/index.d.ts +30 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +30 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/metering.d.ts +209 -0
- package/dist/server/metering.d.ts.map +1 -0
- package/dist/server/metering.js +365 -0
- package/dist/server/metering.js.map +1 -0
- package/dist/server/post-paid.d.ts +355 -0
- package/dist/server/post-paid.d.ts.map +1 -0
- package/dist/server/post-paid.js +512 -0
- package/dist/server/post-paid.js.map +1 -0
- package/dist/x402/client.d.ts +203 -0
- package/dist/x402/client.d.ts.map +1 -0
- package/dist/x402/client.js +337 -0
- package/dist/x402/client.js.map +1 -0
- package/dist/x402/hub.d.ts +79 -0
- package/dist/x402/hub.d.ts.map +1 -0
- package/dist/x402/hub.js +164 -0
- package/dist/x402/hub.js.map +1 -0
- package/dist/x402/index.d.ts +27 -0
- package/dist/x402/index.d.ts.map +1 -0
- package/dist/x402/index.js +27 -0
- package/dist/x402/index.js.map +1 -0
- package/dist/x402/proxy.d.ts +162 -0
- package/dist/x402/proxy.d.ts.map +1 -0
- package/dist/x402/proxy.js +198 -0
- package/dist/x402/proxy.js.map +1 -0
- package/dist/x402/server.d.ts +162 -0
- package/dist/x402/server.d.ts.map +1 -0
- package/dist/x402/server.js +306 -0
- package/dist/x402/server.js.map +1 -0
- package/dist/x402/wire.d.ts +104 -0
- package/dist/x402/wire.d.ts.map +1 -0
- package/dist/x402/wire.js +265 -0
- package/dist/x402/wire.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settle in any asset through Kuru: a strategy that tops the Agent's balance of
|
|
3
|
+
* the Asset up from another token before delegating the Settlement.
|
|
4
|
+
*
|
|
5
|
+
* ## What it does
|
|
6
|
+
*
|
|
7
|
+
* `TabSettlement.settle` moves the Asset the tab is denominated in, and an
|
|
8
|
+
* Agent that holds MON, or a different stablecoin, cannot settle until it holds
|
|
9
|
+
* enough of that Asset. {@link createKuruFundedStrategy} wraps the Monad
|
|
10
|
+
* strategy: before every `settle` it reads the Agent's balance of the Asset,
|
|
11
|
+
* and when it is short, swaps the shortfall in from a configured source token
|
|
12
|
+
* through Kuru, Monad's on-chain order book, and only then settles. The
|
|
13
|
+
* Settlement itself is still the inner strategy's transaction, so the receipt,
|
|
14
|
+
* the `Settled` event and the atomic apply are unchanged.
|
|
15
|
+
*
|
|
16
|
+
* ## The swap is a seam
|
|
17
|
+
*
|
|
18
|
+
* The swap runs through a {@link KuruRouter}: `quote` says how much of the
|
|
19
|
+
* source token buys the shortfall, `swap` executes it. {@link createKuruOnchainRouter}
|
|
20
|
+
* is the shipped implementation over Kuru's `Router.anyToAnySwap`, which is
|
|
21
|
+
* the same entry point on Testnet and Mainnet, driven with a configured route
|
|
22
|
+
* of market addresses. A test hands in a fake router and exercises the whole
|
|
23
|
+
* decision without a chain.
|
|
24
|
+
*
|
|
25
|
+
* ## Why not Kuru's own SDK or its aggregator API
|
|
26
|
+
*
|
|
27
|
+
* `@kuru-labs/kuru-sdk` pins ethers 5 and takes swap amounts as floating
|
|
28
|
+
* point numbers, and the Kuru Flow aggregator API (`ws.kuru.io/api/quote`)
|
|
29
|
+
* needs a bearer token and returns a transaction in a shape the docs do not
|
|
30
|
+
* define. Amounts here are `bigint` base units end to end, so the router talks
|
|
31
|
+
* to the contract directly, with the amounts it was given.
|
|
32
|
+
*
|
|
33
|
+
* ## Amounts
|
|
34
|
+
*
|
|
35
|
+
* `amountOut` is the exact shortfall and is passed as the swap's minimum, so
|
|
36
|
+
* the Settlement is either fully funded or the swap reverts. `amountIn` is a
|
|
37
|
+
* ceiling: the on-chain router quotes by simulation at that ceiling, and the
|
|
38
|
+
* Agent's slippage tolerance sets how much above the quoted price it will pay.
|
|
39
|
+
* Anything the swap returns above the shortfall stays in the Agent's balance.
|
|
40
|
+
*/
|
|
41
|
+
import { Interface, getAddress } from "ethers";
|
|
42
|
+
import { causeOf, isAddress, ok, wrap } from "../_shared/index.js";
|
|
43
|
+
import { chainError, upstreamError, validationError } from "../errors.js";
|
|
44
|
+
import { defaultLogger } from "../logger.js";
|
|
45
|
+
import { ERC20_ABI } from "./abi.js";
|
|
46
|
+
import { assetKey, validateSettleRequest, } from "./strategy.js";
|
|
47
|
+
/** The address Kuru's router reads as the native token, MON. */
|
|
48
|
+
export const KURU_NATIVE_TOKEN = "0x0000000000000000000000000000000000000000";
|
|
49
|
+
/** Kuru's deployments, from its Contract Addresses page. The Router is what `anyToAnySwap` lives on. */
|
|
50
|
+
export const KURU_DEPLOYMENTS = {
|
|
51
|
+
mainnet: {
|
|
52
|
+
chainId: 143n,
|
|
53
|
+
router: "0xd651346d7c789536ebf06dc72aE3C8502cd695CC",
|
|
54
|
+
marginAccount: "0x2A68ba1833cDf93fa9Da1EEbd7F46242aD8E90c5",
|
|
55
|
+
/** The aggregator entry point. Mainnet only: the docs list none for Testnet. */
|
|
56
|
+
flowEntrypoint: "0xb3e6778480b2E488385E8205eA05E20060B813cb",
|
|
57
|
+
wmon: "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
|
|
58
|
+
markets: {
|
|
59
|
+
"MON-USDC": "0x065C9d28E428A0db40191a54d33d5b7c71a9C394",
|
|
60
|
+
"MON-AUSD": "0x131a2e70a5b31a517a74b8c567149bc294470da9",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
testnet: {
|
|
64
|
+
chainId: 10143n,
|
|
65
|
+
router: "0x7EFbE105Ca7415dE98F96622173458ac1c054630",
|
|
66
|
+
marginAccount: "0xd029C2D98ff85D8F64799017fE00a59B1159CE02",
|
|
67
|
+
/** Kuru's own test USDC on Testnet, which is not Tab's `MockUsdc`. */
|
|
68
|
+
usdc: "0x3bA3d39AFcf8bb994f7964B3e0171Ea2Ba361570",
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
const erc20 = new Interface(ERC20_ABI);
|
|
72
|
+
/**
|
|
73
|
+
* Builds the funded strategy. Construction is total.
|
|
74
|
+
*
|
|
75
|
+
* `supports`, `chainIds` and `quote` are the inner strategy's, so registering
|
|
76
|
+
* this in place of it changes nothing about which Assets resolve to it.
|
|
77
|
+
*/
|
|
78
|
+
export function createKuruFundedStrategy(config) {
|
|
79
|
+
const logger = config.logger ?? defaultLogger;
|
|
80
|
+
const id = config.id ?? `${config.inner.id}+kuru`;
|
|
81
|
+
const { inner, kuru } = config;
|
|
82
|
+
const balanceOf = kuru.balanceOf ??
|
|
83
|
+
(async (asset, owner) => {
|
|
84
|
+
const provider = config.signer?.provider;
|
|
85
|
+
if (provider === undefined || provider === null) {
|
|
86
|
+
return upstreamError("KURU_BALANCE_UNREADABLE", `strategy \`${id}\` needs a connected signer, or a balanceOf function, to read the Agent's balance before settling`);
|
|
87
|
+
}
|
|
88
|
+
return wrap(async () => {
|
|
89
|
+
const raw = await provider.call({ to: asset.address, data: erc20.encodeFunctionData("balanceOf", [owner]) });
|
|
90
|
+
return erc20.decodeFunctionResult("balanceOf", raw)[0];
|
|
91
|
+
}, (error) => ({
|
|
92
|
+
category: "UPSTREAM",
|
|
93
|
+
code: "KURU_BALANCE_UNREADABLE",
|
|
94
|
+
message: `strategy \`${id}\` could not read the balance of ${owner} on ${assetKey(asset)}`,
|
|
95
|
+
retryable: true,
|
|
96
|
+
cause: causeOf(error),
|
|
97
|
+
}));
|
|
98
|
+
});
|
|
99
|
+
const fund = async (request) => {
|
|
100
|
+
const agent = getAddress(request.agent);
|
|
101
|
+
const before = await balanceOf(request.asset, agent);
|
|
102
|
+
if (!before.ok)
|
|
103
|
+
return before;
|
|
104
|
+
if (before.value >= request.amount)
|
|
105
|
+
return ok(undefined);
|
|
106
|
+
const shortfall = request.amount - before.value;
|
|
107
|
+
if (kuru.source.address.toLowerCase() === request.asset.address.toLowerCase()) {
|
|
108
|
+
return chainError("KURU_SOURCE_IS_ASSET", `strategy \`${id}\` cannot fund ${assetKey(request.asset)} from itself; the Agent holds ${before.value.toString(10)} and needs ${request.amount.toString(10)}`, { details: { asset: assetKey(request.asset), balance: before.value.toString(10), required: request.amount.toString(10) } });
|
|
109
|
+
}
|
|
110
|
+
const swapRequest = {
|
|
111
|
+
chainId: request.asset.chainId,
|
|
112
|
+
tokenIn: kuru.source.address,
|
|
113
|
+
tokenOut: request.asset.address,
|
|
114
|
+
amountOut: shortfall,
|
|
115
|
+
maxAmountIn: kuru.maxSourceAmount ?? (1n << 128n) - 1n,
|
|
116
|
+
recipient: agent,
|
|
117
|
+
};
|
|
118
|
+
const quoted = await wrap(async () => kuru.router.quote(swapRequest), (error) => ({
|
|
119
|
+
category: "UPSTREAM",
|
|
120
|
+
code: "KURU_ROUTER_THREW",
|
|
121
|
+
message: `strategy \`${id}\`: the Kuru router threw while quoting`,
|
|
122
|
+
retryable: false,
|
|
123
|
+
cause: causeOf(error),
|
|
124
|
+
}));
|
|
125
|
+
if (!quoted.ok)
|
|
126
|
+
return quoted;
|
|
127
|
+
if (!quoted.value.ok)
|
|
128
|
+
return quoted.value;
|
|
129
|
+
const quote = quoted.value.value;
|
|
130
|
+
if (quote.amountIn > swapRequest.maxAmountIn) {
|
|
131
|
+
return chainError("KURU_SOURCE_CEILING", `strategy \`${id}\`: funding ${shortfall.toString(10)} base units of ${request.asset.symbol} needs ${quote.amountIn.toString(10)} of ${kuru.source.symbol}, above the ceiling of ${swapRequest.maxAmountIn.toString(10)}`, { details: { shortfall: shortfall.toString(10), amountIn: quote.amountIn.toString(10), ceiling: swapRequest.maxAmountIn.toString(10) } });
|
|
132
|
+
}
|
|
133
|
+
if (quote.expectedOut < shortfall) {
|
|
134
|
+
return chainError("KURU_QUOTE_SHORT", `strategy \`${id}\`: the Kuru route returns ${quote.expectedOut.toString(10)} for the shortfall of ${shortfall.toString(10)}`, { details: { shortfall: shortfall.toString(10), expectedOut: quote.expectedOut.toString(10) } });
|
|
135
|
+
}
|
|
136
|
+
logger.info("topping the Agent's balance up through Kuru before settling", {
|
|
137
|
+
strategyId: id,
|
|
138
|
+
asset: assetKey(request.asset),
|
|
139
|
+
shortfall: shortfall.toString(10),
|
|
140
|
+
source: kuru.source.symbol,
|
|
141
|
+
amountIn: quote.amountIn.toString(10),
|
|
142
|
+
});
|
|
143
|
+
const swapped = await wrap(async () => kuru.router.swap(quote), (error) => ({
|
|
144
|
+
category: "CHAIN",
|
|
145
|
+
code: "KURU_ROUTER_THREW",
|
|
146
|
+
message: `strategy \`${id}\`: the Kuru router threw while swapping`,
|
|
147
|
+
retryable: false,
|
|
148
|
+
cause: causeOf(error),
|
|
149
|
+
}));
|
|
150
|
+
if (!swapped.ok)
|
|
151
|
+
return swapped;
|
|
152
|
+
if (!swapped.value.ok)
|
|
153
|
+
return swapped.value;
|
|
154
|
+
const after = await balanceOf(request.asset, agent);
|
|
155
|
+
if (!after.ok)
|
|
156
|
+
return after;
|
|
157
|
+
if (after.value < request.amount) {
|
|
158
|
+
return chainError("KURU_SWAP_SHORT", `strategy \`${id}\`: after the swap the Agent holds ${after.value.toString(10)} base units of ${request.asset.symbol}, still short of ${request.amount.toString(10)}`, { details: { balance: after.value.toString(10), required: request.amount.toString(10), txHash: swapped.value.value.txHash } });
|
|
159
|
+
}
|
|
160
|
+
if (kuru.onFunded !== undefined) {
|
|
161
|
+
try {
|
|
162
|
+
kuru.onFunded({ agent, asset: request.asset, balanceBefore: before.value, shortfall, quote, swap: swapped.value.value });
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
logger.warn("onFunded threw and was ignored", causeOf(error));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return ok(undefined);
|
|
169
|
+
};
|
|
170
|
+
const innerBatch = inner.settleBatch;
|
|
171
|
+
return {
|
|
172
|
+
id,
|
|
173
|
+
chainIds: inner.chainIds,
|
|
174
|
+
supports: (asset) => inner.supports(asset),
|
|
175
|
+
async quote(request) {
|
|
176
|
+
const quoted = await inner.quote(request);
|
|
177
|
+
if (!quoted.ok)
|
|
178
|
+
return quoted;
|
|
179
|
+
return ok({
|
|
180
|
+
...quoted.value,
|
|
181
|
+
feeNote: `${quoted.value.feeNote}; a shortfall in ${request.asset.symbol} is swapped in from ${kuru.source.symbol} through Kuru first`,
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
async settle(request) {
|
|
185
|
+
const valid = validateSettleRequest(request);
|
|
186
|
+
if (!valid.ok)
|
|
187
|
+
return valid;
|
|
188
|
+
if (!inner.supports(request.asset)) {
|
|
189
|
+
return validationError("ASSET_NOT_CONFIGURED", `strategy \`${id}\` cannot settle ${assetKey(request.asset)}: the inner strategy does not support it`);
|
|
190
|
+
}
|
|
191
|
+
const funded = await fund(request);
|
|
192
|
+
if (!funded.ok)
|
|
193
|
+
return funded;
|
|
194
|
+
return inner.settle(request);
|
|
195
|
+
},
|
|
196
|
+
...(innerBatch === undefined
|
|
197
|
+
? {}
|
|
198
|
+
: {
|
|
199
|
+
async settleBatch(requests) {
|
|
200
|
+
for (const request of requests) {
|
|
201
|
+
const valid = validateSettleRequest(request);
|
|
202
|
+
if (!valid.ok)
|
|
203
|
+
return valid;
|
|
204
|
+
const funded = await fund(request);
|
|
205
|
+
if (!funded.ok)
|
|
206
|
+
return funded;
|
|
207
|
+
}
|
|
208
|
+
return innerBatch.call(inner, requests);
|
|
209
|
+
},
|
|
210
|
+
}),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
// ---------------------------------------------------------------- the on-chain router
|
|
214
|
+
/** Kuru's `Router.anyToAnySwap`, the multi-hop swap entry point. */
|
|
215
|
+
export const KURU_ROUTER_ABI = [
|
|
216
|
+
"function anyToAnySwap(address[] _marketAddresses, bool[] _isBuy, bool[] _nativeSend, address _debitToken, address _creditToken, uint256 _amount, uint256 _minAmountOut) payable returns (uint256 _amountOut)",
|
|
217
|
+
];
|
|
218
|
+
const routerInterface = new Interface(KURU_ROUTER_ABI);
|
|
219
|
+
/** The key `routes` is looked up by. */
|
|
220
|
+
export const kuruRouteKey = (tokenIn, tokenOut) => `${tokenIn.toLowerCase()}->${tokenOut.toLowerCase()}`;
|
|
221
|
+
/**
|
|
222
|
+
* A router over `anyToAnySwap`.
|
|
223
|
+
*
|
|
224
|
+
* Quoting is a simulation: the swap is `eth_call`ed at a probe size, the
|
|
225
|
+
* price it implies is scaled to the shortfall, and the slippage margin is
|
|
226
|
+
* added. Two probes at most, the second at the computed size, so the quote is
|
|
227
|
+
* checked at the amount that will be sent. The swap is then sent with the
|
|
228
|
+
* shortfall as `_minAmountOut`, which is what makes over-quoting harmless and
|
|
229
|
+
* under-quoting a revert rather than a short Settlement.
|
|
230
|
+
*/
|
|
231
|
+
export function createKuruOnchainRouter(options) {
|
|
232
|
+
const logger = options.logger ?? defaultLogger;
|
|
233
|
+
const slippageBps = BigInt(options.slippageBps ?? 100);
|
|
234
|
+
const routeFor = (request) => {
|
|
235
|
+
const route = options.routes[kuruRouteKey(request.tokenIn, request.tokenOut)];
|
|
236
|
+
if (route === undefined) {
|
|
237
|
+
return validationError("KURU_ROUTE_UNKNOWN", `no Kuru route is configured from ${request.tokenIn} to ${request.tokenOut}`, {
|
|
238
|
+
details: { tokenIn: request.tokenIn, tokenOut: request.tokenOut, configured: Object.keys(options.routes).join(", ") },
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
if (route.markets.length === 0 || route.isBuy.length !== route.markets.length || route.nativeSend.length !== route.markets.length) {
|
|
242
|
+
return validationError("KURU_ROUTE_INVALID", "a Kuru route needs one market, one isBuy and one nativeSend per hop");
|
|
243
|
+
}
|
|
244
|
+
for (const market of route.markets) {
|
|
245
|
+
if (!isAddress(market))
|
|
246
|
+
return validationError("KURU_ROUTE_INVALID", `market \`${market}\` is not a 20-byte address`);
|
|
247
|
+
}
|
|
248
|
+
return ok(route);
|
|
249
|
+
};
|
|
250
|
+
const calldata = (route, request, amountIn, minOut) => routerInterface.encodeFunctionData("anyToAnySwap", [
|
|
251
|
+
[...route.markets],
|
|
252
|
+
[...route.isBuy],
|
|
253
|
+
[...route.nativeSend],
|
|
254
|
+
request.tokenIn,
|
|
255
|
+
request.tokenOut,
|
|
256
|
+
amountIn,
|
|
257
|
+
minOut,
|
|
258
|
+
]);
|
|
259
|
+
const native = (route) => route.nativeSend[0] === true;
|
|
260
|
+
const simulate = async (route, request, amountIn) => {
|
|
261
|
+
const provider = options.signer.provider;
|
|
262
|
+
if (provider === undefined || provider === null) {
|
|
263
|
+
return upstreamError("KURU_QUOTE_UNAVAILABLE", "the Kuru router needs a connected signer to simulate a swap");
|
|
264
|
+
}
|
|
265
|
+
return wrap(async () => {
|
|
266
|
+
const raw = await provider.call({
|
|
267
|
+
to: options.router,
|
|
268
|
+
data: calldata(route, request, amountIn, 0n),
|
|
269
|
+
...(native(route) ? { value: amountIn, from: await options.signer.getAddress() } : { from: await options.signer.getAddress() }),
|
|
270
|
+
});
|
|
271
|
+
return routerInterface.decodeFunctionResult("anyToAnySwap", raw)[0];
|
|
272
|
+
}, (error) => ({
|
|
273
|
+
category: "UPSTREAM",
|
|
274
|
+
code: "KURU_QUOTE_FAILED",
|
|
275
|
+
message: `the Kuru router at ${options.router} could not simulate the swap`,
|
|
276
|
+
retryable: true,
|
|
277
|
+
details: { amountIn: amountIn.toString(10) },
|
|
278
|
+
cause: causeOf(error),
|
|
279
|
+
}));
|
|
280
|
+
};
|
|
281
|
+
const ceilDiv = (numerator, denominator) => (numerator + denominator - 1n) / denominator;
|
|
282
|
+
return {
|
|
283
|
+
async quote(request) {
|
|
284
|
+
const route = routeFor(request);
|
|
285
|
+
if (!route.ok)
|
|
286
|
+
return route;
|
|
287
|
+
if (request.amountOut <= 0n)
|
|
288
|
+
return validationError("KURU_AMOUNT_INVALID", "amountOut must be positive");
|
|
289
|
+
const probe = options.probeAmountIn ?? request.maxAmountIn;
|
|
290
|
+
if (probe <= 0n)
|
|
291
|
+
return validationError("KURU_AMOUNT_INVALID", "the probe amount must be positive; set maxSourceAmount or probeAmountIn");
|
|
292
|
+
const outAtProbe = await simulate(route.value, request, probe);
|
|
293
|
+
if (!outAtProbe.ok)
|
|
294
|
+
return outAtProbe;
|
|
295
|
+
if (outAtProbe.value <= 0n) {
|
|
296
|
+
return chainError("KURU_QUOTE_SHORT", `the Kuru route returns nothing for ${probe.toString(10)} of ${request.tokenIn}`, {
|
|
297
|
+
details: { probe: probe.toString(10) },
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
// Price implied at the probe, scaled to the shortfall, then the margin.
|
|
301
|
+
let amountIn = ceilDiv(request.amountOut * probe, outAtProbe.value);
|
|
302
|
+
amountIn = ceilDiv(amountIn * (10000n + slippageBps), 10000n);
|
|
303
|
+
if (amountIn > request.maxAmountIn)
|
|
304
|
+
amountIn = request.maxAmountIn;
|
|
305
|
+
const expected = amountIn === probe ? outAtProbe : await simulate(route.value, request, amountIn);
|
|
306
|
+
if (!expected.ok)
|
|
307
|
+
return expected;
|
|
308
|
+
if (expected.value < request.amountOut) {
|
|
309
|
+
// Depth is worse at the size to be sent than the probe implied. One
|
|
310
|
+
// more step up, bounded by the ceiling; past that it is not fundable.
|
|
311
|
+
const stepped = amountIn >= request.maxAmountIn ? amountIn : ceilDiv(amountIn * request.amountOut, expected.value);
|
|
312
|
+
const bounded = stepped > request.maxAmountIn ? request.maxAmountIn : stepped;
|
|
313
|
+
const again = bounded === amountIn ? expected : await simulate(route.value, request, bounded);
|
|
314
|
+
if (!again.ok)
|
|
315
|
+
return again;
|
|
316
|
+
if (again.value < request.amountOut) {
|
|
317
|
+
return chainError("KURU_QUOTE_SHORT", `the Kuru route returns ${again.value.toString(10)} for ${bounded.toString(10)} of ${request.tokenIn}, short of ${request.amountOut.toString(10)}`, {
|
|
318
|
+
details: { amountIn: bounded.toString(10), expectedOut: again.value.toString(10), amountOut: request.amountOut.toString(10) },
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
return ok({ request, amountIn: bounded, expectedOut: again.value });
|
|
322
|
+
}
|
|
323
|
+
return ok({ request, amountIn, expectedOut: expected.value });
|
|
324
|
+
},
|
|
325
|
+
async swap(quote) {
|
|
326
|
+
const route = routeFor(quote.request);
|
|
327
|
+
if (!route.ok)
|
|
328
|
+
return route;
|
|
329
|
+
const { request } = quote;
|
|
330
|
+
if (!native(route.value)) {
|
|
331
|
+
const owner = await options.signer.getAddress();
|
|
332
|
+
const approved = await wrap(async () => options.signer.sendTransaction({ to: request.tokenIn, data: erc20.encodeFunctionData("approve", [options.router, quote.amountIn]) }), (error) => ({
|
|
333
|
+
category: "CHAIN",
|
|
334
|
+
code: "KURU_APPROVE_FAILED",
|
|
335
|
+
message: `the allowance for Kuru's router on ${request.tokenIn} could not be set`,
|
|
336
|
+
retryable: false,
|
|
337
|
+
details: { owner },
|
|
338
|
+
cause: causeOf(error),
|
|
339
|
+
}));
|
|
340
|
+
if (!approved.ok)
|
|
341
|
+
return approved;
|
|
342
|
+
await settleTx(approved.value, logger);
|
|
343
|
+
}
|
|
344
|
+
const sent = await wrap(async () => options.signer.sendTransaction({
|
|
345
|
+
to: options.router,
|
|
346
|
+
data: calldata(route.value, request, quote.amountIn, request.amountOut),
|
|
347
|
+
...(native(route.value) ? { value: quote.amountIn } : {}),
|
|
348
|
+
}), (error) => ({
|
|
349
|
+
category: "CHAIN",
|
|
350
|
+
code: "KURU_SWAP_FAILED",
|
|
351
|
+
message: `the Kuru swap through ${options.router} could not be sent`,
|
|
352
|
+
retryable: false,
|
|
353
|
+
cause: causeOf(error),
|
|
354
|
+
}));
|
|
355
|
+
if (!sent.ok)
|
|
356
|
+
return sent;
|
|
357
|
+
const receipt = await settleTx(sent.value, logger);
|
|
358
|
+
if (receipt !== null && receipt.status === 0) {
|
|
359
|
+
return chainError("KURU_SWAP_REVERTED", `the Kuru swap ${sent.value.hash} reverted`, { details: { txHash: sent.value.hash } });
|
|
360
|
+
}
|
|
361
|
+
return ok({ txHash: sent.value.hash, amountIn: quote.amountIn, amountOut: quote.expectedOut });
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
/** Waits for a transaction where the signer can, and shrugs where it cannot. */
|
|
366
|
+
async function settleTx(response, logger) {
|
|
367
|
+
if (typeof response.wait !== "function")
|
|
368
|
+
return null;
|
|
369
|
+
try {
|
|
370
|
+
return await response.wait();
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
logger.warn("could not wait for a Kuru transaction", { txHash: response.hash, error: causeOf(error).message });
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
//# sourceMappingURL=kuru.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kuru.js","sourceRoot":"","sources":["../../src/payments/kuru.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Settle in any asset through Kuru: a strategy that tops the Agent's balance of\n * the Asset up from another token before delegating the Settlement.\n *\n * ## What it does\n *\n * `TabSettlement.settle` moves the Asset the tab is denominated in, and an\n * Agent that holds MON, or a different stablecoin, cannot settle until it holds\n * enough of that Asset. {@link createKuruFundedStrategy} wraps the Monad\n * strategy: before every `settle` it reads the Agent's balance of the Asset,\n * and when it is short, swaps the shortfall in from a configured source token\n * through Kuru, Monad's on-chain order book, and only then settles. The\n * Settlement itself is still the inner strategy's transaction, so the receipt,\n * the `Settled` event and the atomic apply are unchanged.\n *\n * ## The swap is a seam\n *\n * The swap runs through a {@link KuruRouter}: `quote` says how much of the\n * source token buys the shortfall, `swap` executes it. {@link createKuruOnchainRouter}\n * is the shipped implementation over Kuru's `Router.anyToAnySwap`, which is\n * the same entry point on Testnet and Mainnet, driven with a configured route\n * of market addresses. A test hands in a fake router and exercises the whole\n * decision without a chain.\n *\n * ## Why not Kuru's own SDK or its aggregator API\n *\n * `@kuru-labs/kuru-sdk` pins ethers 5 and takes swap amounts as floating\n * point numbers, and the Kuru Flow aggregator API (`ws.kuru.io/api/quote`)\n * needs a bearer token and returns a transaction in a shape the docs do not\n * define. Amounts here are `bigint` base units end to end, so the router talks\n * to the contract directly, with the amounts it was given.\n *\n * ## Amounts\n *\n * `amountOut` is the exact shortfall and is passed as the swap's minimum, so\n * the Settlement is either fully funded or the swap reverts. `amountIn` is a\n * ceiling: the on-chain router quotes by simulation at that ceiling, and the\n * Agent's slippage tolerance sets how much above the quoted price it will pay.\n * Anything the swap returns above the shortfall stays in the Agent's balance.\n */\n\nimport { Interface, getAddress } from \"ethers\";\nimport { causeOf, isAddress, ok, wrap, type Address, type Hex, type Result } from \"../_shared/index.js\";\n\nimport { chainError, upstreamError, validationError } from \"../errors.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport { ERC20_ABI } from \"./abi.js\";\nimport type { EthersV6Signer, EthersV6TransactionResponse } from \"./monad.js\";\nimport {\n assetKey,\n validateSettleRequest,\n type AssetRef,\n type ChargeQuote,\n type ChargeRequest,\n type PaymentStrategy,\n type SettleRequest,\n type SettlementReceipt,\n} from \"./strategy.js\";\n\n/** The address Kuru's router reads as the native token, MON. */\nexport const KURU_NATIVE_TOKEN: Address = \"0x0000000000000000000000000000000000000000\";\n\n/** Kuru's deployments, from its Contract Addresses page. The Router is what `anyToAnySwap` lives on. */\nexport const KURU_DEPLOYMENTS = {\n mainnet: {\n chainId: 143n,\n router: \"0xd651346d7c789536ebf06dc72aE3C8502cd695CC\" as Address,\n marginAccount: \"0x2A68ba1833cDf93fa9Da1EEbd7F46242aD8E90c5\" as Address,\n /** The aggregator entry point. Mainnet only: the docs list none for Testnet. */\n flowEntrypoint: \"0xb3e6778480b2E488385E8205eA05E20060B813cb\" as Address,\n wmon: \"0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A\" as Address,\n markets: {\n \"MON-USDC\": \"0x065C9d28E428A0db40191a54d33d5b7c71a9C394\" as Address,\n \"MON-AUSD\": \"0x131a2e70a5b31a517a74b8c567149bc294470da9\" as Address,\n },\n },\n testnet: {\n chainId: 10143n,\n router: \"0x7EFbE105Ca7415dE98F96622173458ac1c054630\" as Address,\n marginAccount: \"0xd029C2D98ff85D8F64799017fE00a59B1159CE02\" as Address,\n /** Kuru's own test USDC on Testnet, which is not Tab's `MockUsdc`. */\n usdc: \"0x3bA3d39AFcf8bb994f7964B3e0171Ea2Ba361570\" as Address,\n },\n} as const;\n\n/** The source token a swap draws from. `address` is {@link KURU_NATIVE_TOKEN} for MON. */\nexport interface KuruSourceToken {\n readonly address: Address;\n readonly decimals: number;\n readonly symbol: string;\n}\n\n/** What the router is asked for. */\nexport interface KuruSwapRequest {\n readonly chainId: bigint;\n readonly tokenIn: Address;\n readonly tokenOut: Address;\n /** The exact shortfall in `tokenOut` base units. The swap must return at least this. */\n readonly amountOut: bigint;\n /** The most `tokenIn` the caller will spend. */\n readonly maxAmountIn: bigint;\n /** Where the output lands. The Agent, always. */\n readonly recipient: Address;\n}\n\nexport interface KuruQuote {\n readonly request: KuruSwapRequest;\n /** How much `tokenIn` the swap will be sent with. At most `request.maxAmountIn`. */\n readonly amountIn: bigint;\n /** What the router expects back. At least `request.amountOut`. */\n readonly expectedOut: bigint;\n}\n\nexport interface KuruSwapReceipt {\n readonly txHash: Hex;\n readonly amountIn: bigint;\n /** What the swap returned, when the router could read it; the quote's expectation otherwise. */\n readonly amountOut: bigint;\n}\n\n/** The swap seam. Both methods return a `Result`, never throw. */\nexport interface KuruRouter {\n quote(request: KuruSwapRequest): Promise<Result<KuruQuote>>;\n swap(quote: KuruQuote): Promise<Result<KuruSwapReceipt>>;\n}\n\nexport interface KuruConfig {\n readonly router: KuruRouter;\n readonly source: KuruSourceToken;\n /**\n * Reads the Agent's balance of an Asset. Defaults to `balanceOf` through the\n * inner signer's provider when `signer` is given; required otherwise.\n */\n readonly balanceOf?: (asset: AssetRef, owner: Address) => Promise<Result<bigint>>;\n /** The most of the source token one Settlement may spend. Omitted sets no ceiling. */\n readonly maxSourceAmount?: bigint;\n /** Called with every swap that funded a Settlement. */\n readonly onFunded?: (event: KuruFundingEvent) => void;\n}\n\n/** One top-up, as reported after the Settlement it funded. */\nexport interface KuruFundingEvent {\n readonly agent: Address;\n readonly asset: AssetRef;\n readonly balanceBefore: bigint;\n readonly shortfall: bigint;\n readonly quote: KuruQuote;\n readonly swap: KuruSwapReceipt;\n}\n\nexport interface KuruFundedStrategyConfig {\n /** The strategy that settles once the balance is there. The Monad strategy, ordinarily. */\n readonly inner: PaymentStrategy;\n readonly kuru: KuruConfig;\n /**\n * The Agent's signer, for the default `balanceOf`. Its `provider` is what the\n * balance is read through. Not needed when `kuru.balanceOf` is supplied.\n */\n readonly signer?: EthersV6Signer;\n readonly id?: string;\n readonly logger?: Logger;\n}\n\nconst erc20 = new Interface(ERC20_ABI);\n\n/**\n * Builds the funded strategy. Construction is total.\n *\n * `supports`, `chainIds` and `quote` are the inner strategy's, so registering\n * this in place of it changes nothing about which Assets resolve to it.\n */\nexport function createKuruFundedStrategy(config: KuruFundedStrategyConfig): PaymentStrategy {\n const logger = config.logger ?? defaultLogger;\n const id = config.id ?? `${config.inner.id}+kuru`;\n const { inner, kuru } = config;\n\n const balanceOf: (asset: AssetRef, owner: Address) => Promise<Result<bigint>> =\n kuru.balanceOf ??\n (async (asset, owner) => {\n const provider = config.signer?.provider;\n if (provider === undefined || provider === null) {\n return upstreamError(\n \"KURU_BALANCE_UNREADABLE\",\n `strategy \\`${id}\\` needs a connected signer, or a balanceOf function, to read the Agent's balance before settling`,\n );\n }\n return wrap(\n async () => {\n const raw = await provider.call({ to: asset.address, data: erc20.encodeFunctionData(\"balanceOf\", [owner]) });\n return erc20.decodeFunctionResult(\"balanceOf\", raw)[0] as bigint;\n },\n (error) => ({\n category: \"UPSTREAM\" as const,\n code: \"KURU_BALANCE_UNREADABLE\",\n message: `strategy \\`${id}\\` could not read the balance of ${owner} on ${assetKey(asset)}`,\n retryable: true,\n cause: causeOf(error),\n }),\n );\n });\n\n const fund = async (request: SettleRequest): Promise<Result<void>> => {\n const agent = getAddress(request.agent) as Address;\n const before = await balanceOf(request.asset, agent);\n if (!before.ok) return before;\n if (before.value >= request.amount) return ok(undefined);\n\n const shortfall = request.amount - before.value;\n if (kuru.source.address.toLowerCase() === request.asset.address.toLowerCase()) {\n return chainError(\n \"KURU_SOURCE_IS_ASSET\",\n `strategy \\`${id}\\` cannot fund ${assetKey(request.asset)} from itself; the Agent holds ${before.value.toString(10)} and needs ${request.amount.toString(10)}`,\n { details: { asset: assetKey(request.asset), balance: before.value.toString(10), required: request.amount.toString(10) } },\n );\n }\n const swapRequest: KuruSwapRequest = {\n chainId: request.asset.chainId,\n tokenIn: kuru.source.address,\n tokenOut: request.asset.address,\n amountOut: shortfall,\n maxAmountIn: kuru.maxSourceAmount ?? (1n << 128n) - 1n,\n recipient: agent,\n };\n\n const quoted = await wrap(\n async () => kuru.router.quote(swapRequest),\n (error) => ({\n category: \"UPSTREAM\" as const,\n code: \"KURU_ROUTER_THREW\",\n message: `strategy \\`${id}\\`: the Kuru router threw while quoting`,\n retryable: false,\n cause: causeOf(error),\n }),\n );\n if (!quoted.ok) return quoted;\n if (!quoted.value.ok) return quoted.value;\n const quote = quoted.value.value;\n if (quote.amountIn > swapRequest.maxAmountIn) {\n return chainError(\n \"KURU_SOURCE_CEILING\",\n `strategy \\`${id}\\`: funding ${shortfall.toString(10)} base units of ${request.asset.symbol} needs ${quote.amountIn.toString(10)} of ${kuru.source.symbol}, above the ceiling of ${swapRequest.maxAmountIn.toString(10)}`,\n { details: { shortfall: shortfall.toString(10), amountIn: quote.amountIn.toString(10), ceiling: swapRequest.maxAmountIn.toString(10) } },\n );\n }\n if (quote.expectedOut < shortfall) {\n return chainError(\n \"KURU_QUOTE_SHORT\",\n `strategy \\`${id}\\`: the Kuru route returns ${quote.expectedOut.toString(10)} for the shortfall of ${shortfall.toString(10)}`,\n { details: { shortfall: shortfall.toString(10), expectedOut: quote.expectedOut.toString(10) } },\n );\n }\n\n logger.info(\"topping the Agent's balance up through Kuru before settling\", {\n strategyId: id,\n asset: assetKey(request.asset),\n shortfall: shortfall.toString(10),\n source: kuru.source.symbol,\n amountIn: quote.amountIn.toString(10),\n });\n const swapped = await wrap(\n async () => kuru.router.swap(quote),\n (error) => ({\n category: \"CHAIN\" as const,\n code: \"KURU_ROUTER_THREW\",\n message: `strategy \\`${id}\\`: the Kuru router threw while swapping`,\n retryable: false,\n cause: causeOf(error),\n }),\n );\n if (!swapped.ok) return swapped;\n if (!swapped.value.ok) return swapped.value;\n\n const after = await balanceOf(request.asset, agent);\n if (!after.ok) return after;\n if (after.value < request.amount) {\n return chainError(\n \"KURU_SWAP_SHORT\",\n `strategy \\`${id}\\`: after the swap the Agent holds ${after.value.toString(10)} base units of ${request.asset.symbol}, still short of ${request.amount.toString(10)}`,\n { details: { balance: after.value.toString(10), required: request.amount.toString(10), txHash: swapped.value.value.txHash } },\n );\n }\n if (kuru.onFunded !== undefined) {\n try {\n kuru.onFunded({ agent, asset: request.asset, balanceBefore: before.value, shortfall, quote, swap: swapped.value.value });\n } catch (error) {\n logger.warn(\"onFunded threw and was ignored\", causeOf(error));\n }\n }\n return ok(undefined);\n };\n\n const innerBatch = inner.settleBatch;\n\n return {\n id,\n chainIds: inner.chainIds,\n supports: (asset: AssetRef) => inner.supports(asset),\n async quote(request: ChargeRequest): Promise<Result<ChargeQuote>> {\n const quoted = await inner.quote(request);\n if (!quoted.ok) return quoted;\n return ok({\n ...quoted.value,\n feeNote: `${quoted.value.feeNote}; a shortfall in ${request.asset.symbol} is swapped in from ${kuru.source.symbol} through Kuru first`,\n });\n },\n async settle(request: SettleRequest): Promise<Result<SettlementReceipt>> {\n const valid = validateSettleRequest(request);\n if (!valid.ok) return valid;\n if (!inner.supports(request.asset)) {\n return validationError(\"ASSET_NOT_CONFIGURED\", `strategy \\`${id}\\` cannot settle ${assetKey(request.asset)}: the inner strategy does not support it`);\n }\n const funded = await fund(request);\n if (!funded.ok) return funded;\n return inner.settle(request);\n },\n ...(innerBatch === undefined\n ? {}\n : {\n async settleBatch(requests: readonly SettleRequest[]): Promise<Result<readonly SettlementReceipt[]>> {\n for (const request of requests) {\n const valid = validateSettleRequest(request);\n if (!valid.ok) return valid;\n const funded = await fund(request);\n if (!funded.ok) return funded;\n }\n return innerBatch.call(inner, requests);\n },\n }),\n };\n}\n\n// ---------------------------------------------------------------- the on-chain router\n\n/** Kuru's `Router.anyToAnySwap`, the multi-hop swap entry point. */\nexport const KURU_ROUTER_ABI = [\n \"function anyToAnySwap(address[] _marketAddresses, bool[] _isBuy, bool[] _nativeSend, address _debitToken, address _creditToken, uint256 _amount, uint256 _minAmountOut) payable returns (uint256 _amountOut)\",\n] as const;\n\n/**\n * One route through Kuru's markets, as `anyToAnySwap` takes it.\n *\n * Every array is per hop. `isBuy` says whether the hop buys the market's base\n * with its quote, `nativeSend` whether the hop is paid in MON. The MON-USDC\n * market on Mainnet, selling MON for USDC, is one hop: `{ markets: [MON_USDC],\n * isBuy: [false], nativeSend: [true] }`.\n */\nexport interface KuruRoute {\n readonly markets: readonly Address[];\n readonly isBuy: readonly boolean[];\n readonly nativeSend: readonly boolean[];\n}\n\n/** What the on-chain router needs of a signer: a call for the quote, a send for the swap. An `ethers.Signer` satisfies it. */\nexport type KuruSigner = EthersV6Signer;\n\nexport interface KuruOnchainRouterOptions {\n readonly signer: KuruSigner;\n /** Kuru's Router on the chain the signer is on. */\n readonly router: Address;\n /** Routes keyed by `${tokenIn}->${tokenOut}`, lower-cased. */\n readonly routes: Readonly<Record<string, KuruRoute>>;\n /** How far above the simulated price the swap may pay. Defaults to 100, one percent. */\n readonly slippageBps?: number;\n /**\n * The `tokenIn` amount the price is probed at. Defaults to `maxAmountIn`.\n * Probing at the size to be swapped keeps the quote honest about depth.\n */\n readonly probeAmountIn?: bigint;\n readonly logger?: Logger;\n}\n\nconst routerInterface = new Interface(KURU_ROUTER_ABI);\n\n/** The key `routes` is looked up by. */\nexport const kuruRouteKey = (tokenIn: string, tokenOut: string): string => `${tokenIn.toLowerCase()}->${tokenOut.toLowerCase()}`;\n\n/**\n * A router over `anyToAnySwap`.\n *\n * Quoting is a simulation: the swap is `eth_call`ed at a probe size, the\n * price it implies is scaled to the shortfall, and the slippage margin is\n * added. Two probes at most, the second at the computed size, so the quote is\n * checked at the amount that will be sent. The swap is then sent with the\n * shortfall as `_minAmountOut`, which is what makes over-quoting harmless and\n * under-quoting a revert rather than a short Settlement.\n */\nexport function createKuruOnchainRouter(options: KuruOnchainRouterOptions): KuruRouter {\n const logger = options.logger ?? defaultLogger;\n const slippageBps = BigInt(options.slippageBps ?? 100);\n\n const routeFor = (request: KuruSwapRequest): Result<KuruRoute> => {\n const route = options.routes[kuruRouteKey(request.tokenIn, request.tokenOut)];\n if (route === undefined) {\n return validationError(\"KURU_ROUTE_UNKNOWN\", `no Kuru route is configured from ${request.tokenIn} to ${request.tokenOut}`, {\n details: { tokenIn: request.tokenIn, tokenOut: request.tokenOut, configured: Object.keys(options.routes).join(\", \") },\n });\n }\n if (route.markets.length === 0 || route.isBuy.length !== route.markets.length || route.nativeSend.length !== route.markets.length) {\n return validationError(\"KURU_ROUTE_INVALID\", \"a Kuru route needs one market, one isBuy and one nativeSend per hop\");\n }\n for (const market of route.markets) {\n if (!isAddress(market)) return validationError(\"KURU_ROUTE_INVALID\", `market \\`${market}\\` is not a 20-byte address`);\n }\n return ok(route);\n };\n\n const calldata = (route: KuruRoute, request: KuruSwapRequest, amountIn: bigint, minOut: bigint): string =>\n routerInterface.encodeFunctionData(\"anyToAnySwap\", [\n [...route.markets],\n [...route.isBuy],\n [...route.nativeSend],\n request.tokenIn,\n request.tokenOut,\n amountIn,\n minOut,\n ]);\n\n const native = (route: KuruRoute): boolean => route.nativeSend[0] === true;\n\n const simulate = async (route: KuruRoute, request: KuruSwapRequest, amountIn: bigint): Promise<Result<bigint>> => {\n const provider = options.signer.provider;\n if (provider === undefined || provider === null) {\n return upstreamError(\"KURU_QUOTE_UNAVAILABLE\", \"the Kuru router needs a connected signer to simulate a swap\");\n }\n return wrap(\n async () => {\n const raw = await provider.call({\n to: options.router,\n data: calldata(route, request, amountIn, 0n),\n ...(native(route) ? { value: amountIn, from: await options.signer.getAddress() } : { from: await options.signer.getAddress() }),\n } as { to: string; data: string });\n return routerInterface.decodeFunctionResult(\"anyToAnySwap\", raw)[0] as bigint;\n },\n (error) => ({\n category: \"UPSTREAM\" as const,\n code: \"KURU_QUOTE_FAILED\",\n message: `the Kuru router at ${options.router} could not simulate the swap`,\n retryable: true,\n details: { amountIn: amountIn.toString(10) },\n cause: causeOf(error),\n }),\n );\n };\n\n const ceilDiv = (numerator: bigint, denominator: bigint): bigint => (numerator + denominator - 1n) / denominator;\n\n return {\n async quote(request) {\n const route = routeFor(request);\n if (!route.ok) return route;\n if (request.amountOut <= 0n) return validationError(\"KURU_AMOUNT_INVALID\", \"amountOut must be positive\");\n const probe = options.probeAmountIn ?? request.maxAmountIn;\n if (probe <= 0n) return validationError(\"KURU_AMOUNT_INVALID\", \"the probe amount must be positive; set maxSourceAmount or probeAmountIn\");\n\n const outAtProbe = await simulate(route.value, request, probe);\n if (!outAtProbe.ok) return outAtProbe;\n if (outAtProbe.value <= 0n) {\n return chainError(\"KURU_QUOTE_SHORT\", `the Kuru route returns nothing for ${probe.toString(10)} of ${request.tokenIn}`, {\n details: { probe: probe.toString(10) },\n });\n }\n\n // Price implied at the probe, scaled to the shortfall, then the margin.\n let amountIn = ceilDiv(request.amountOut * probe, outAtProbe.value);\n amountIn = ceilDiv(amountIn * (10_000n + slippageBps), 10_000n);\n if (amountIn > request.maxAmountIn) amountIn = request.maxAmountIn;\n\n const expected = amountIn === probe ? outAtProbe : await simulate(route.value, request, amountIn);\n if (!expected.ok) return expected;\n if (expected.value < request.amountOut) {\n // Depth is worse at the size to be sent than the probe implied. One\n // more step up, bounded by the ceiling; past that it is not fundable.\n const stepped = amountIn >= request.maxAmountIn ? amountIn : ceilDiv(amountIn * request.amountOut, expected.value);\n const bounded = stepped > request.maxAmountIn ? request.maxAmountIn : stepped;\n const again = bounded === amountIn ? expected : await simulate(route.value, request, bounded);\n if (!again.ok) return again;\n if (again.value < request.amountOut) {\n return chainError(\"KURU_QUOTE_SHORT\", `the Kuru route returns ${again.value.toString(10)} for ${bounded.toString(10)} of ${request.tokenIn}, short of ${request.amountOut.toString(10)}`, {\n details: { amountIn: bounded.toString(10), expectedOut: again.value.toString(10), amountOut: request.amountOut.toString(10) },\n });\n }\n return ok({ request, amountIn: bounded, expectedOut: again.value });\n }\n return ok({ request, amountIn, expectedOut: expected.value });\n },\n\n async swap(quote) {\n const route = routeFor(quote.request);\n if (!route.ok) return route;\n const { request } = quote;\n\n if (!native(route.value)) {\n const owner = await options.signer.getAddress();\n const approved = await wrap(\n async () => options.signer.sendTransaction({ to: request.tokenIn, data: erc20.encodeFunctionData(\"approve\", [options.router, quote.amountIn]) }),\n (error) => ({\n category: \"CHAIN\" as const,\n code: \"KURU_APPROVE_FAILED\",\n message: `the allowance for Kuru's router on ${request.tokenIn} could not be set`,\n retryable: false,\n details: { owner },\n cause: causeOf(error),\n }),\n );\n if (!approved.ok) return approved;\n await settleTx(approved.value, logger);\n }\n\n const sent = await wrap(\n async () =>\n options.signer.sendTransaction({\n to: options.router,\n data: calldata(route.value, request, quote.amountIn, request.amountOut),\n ...(native(route.value) ? { value: quote.amountIn } : {}),\n }),\n (error) => ({\n category: \"CHAIN\" as const,\n code: \"KURU_SWAP_FAILED\",\n message: `the Kuru swap through ${options.router} could not be sent`,\n retryable: false,\n cause: causeOf(error),\n }),\n );\n if (!sent.ok) return sent;\n const receipt = await settleTx(sent.value, logger);\n if (receipt !== null && receipt.status === 0) {\n return chainError(\"KURU_SWAP_REVERTED\", `the Kuru swap ${sent.value.hash} reverted`, { details: { txHash: sent.value.hash } });\n }\n return ok({ txHash: sent.value.hash as Hex, amountIn: quote.amountIn, amountOut: quote.expectedOut });\n },\n };\n}\n\n/** Waits for a transaction where the signer can, and shrugs where it cannot. */\nasync function settleTx(response: EthersV6TransactionResponse, logger: Logger): Promise<{ status: number | null } | null> {\n if (typeof response.wait !== \"function\") return null;\n try {\n return await response.wait();\n } catch (error) {\n logger.warn(\"could not wait for a Kuru transaction\", { txHash: response.hash, error: causeOf(error).message });\n return null;\n }\n}\n"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Signer } from "ethers";
|
|
2
|
+
import { type Address, type Bytes32 } from "../_shared/index.js";
|
|
3
|
+
import { type Logger } from "../logger.js";
|
|
4
|
+
import { type AssetRef, type PaymentStrategy } from "./strategy.js";
|
|
5
|
+
export declare const MONAD_STRATEGY_ID = "monad";
|
|
6
|
+
export interface EthersV6TransactionRequest {
|
|
7
|
+
readonly to: string;
|
|
8
|
+
readonly data: string;
|
|
9
|
+
readonly value?: bigint;
|
|
10
|
+
}
|
|
11
|
+
/** One log as the receipt carries it. */
|
|
12
|
+
export interface EthersV6Log {
|
|
13
|
+
readonly address: string;
|
|
14
|
+
readonly topics: readonly string[];
|
|
15
|
+
readonly data: string;
|
|
16
|
+
}
|
|
17
|
+
export interface EthersV6TransactionReceipt {
|
|
18
|
+
readonly hash: string;
|
|
19
|
+
readonly status: number | null;
|
|
20
|
+
readonly logs: readonly EthersV6Log[];
|
|
21
|
+
}
|
|
22
|
+
export interface EthersV6TransactionResponse {
|
|
23
|
+
readonly hash: string;
|
|
24
|
+
wait?(confirmations?: number): Promise<EthersV6TransactionReceipt | null>;
|
|
25
|
+
}
|
|
26
|
+
export interface EthersV6CallProvider {
|
|
27
|
+
call(transaction: {
|
|
28
|
+
readonly to: string;
|
|
29
|
+
readonly data: string;
|
|
30
|
+
}): Promise<string>;
|
|
31
|
+
}
|
|
32
|
+
export interface EthersV6Signer {
|
|
33
|
+
getAddress(): Promise<string>;
|
|
34
|
+
sendTransaction(transaction: EthersV6TransactionRequest): Promise<EthersV6TransactionResponse>;
|
|
35
|
+
readonly provider?: EthersV6CallProvider | null;
|
|
36
|
+
}
|
|
37
|
+
type Assert<T extends true> = T;
|
|
38
|
+
type SignerIsAccepted = Assert<Signer extends EthersV6Signer ? true : false>;
|
|
39
|
+
export type EthersV6SignerAcceptsEthersSigner = SignerIsAccepted;
|
|
40
|
+
export interface MonadStrategyConfig {
|
|
41
|
+
readonly signer: EthersV6Signer;
|
|
42
|
+
/** The deployed `TabSettlement`. */
|
|
43
|
+
readonly tabSettlement: Address;
|
|
44
|
+
/** The Assets this strategy will settle in, keyed by `<chainId>:<address>`. */
|
|
45
|
+
readonly assets: Readonly<Record<string, AssetRef>>;
|
|
46
|
+
readonly id?: string;
|
|
47
|
+
/** `exact` approves each amount; `unlimited` approves once. Default `exact`. */
|
|
48
|
+
readonly approval?: "exact" | "unlimited";
|
|
49
|
+
/** `skip` sends without reading the allowance first, for a signer with no provider. */
|
|
50
|
+
readonly allowanceCheck?: "read" | "skip";
|
|
51
|
+
/** Whether to wait for the receipt and decode the Settlement from it. Default `wait`. */
|
|
52
|
+
readonly receipt?: "wait" | "skip";
|
|
53
|
+
readonly logger?: Logger;
|
|
54
|
+
readonly now?: () => number;
|
|
55
|
+
}
|
|
56
|
+
/** What one `Settled` log says. */
|
|
57
|
+
export interface SettledLog {
|
|
58
|
+
readonly settlementId: Bytes32;
|
|
59
|
+
readonly agent: Address;
|
|
60
|
+
readonly serviceId: Bytes32;
|
|
61
|
+
readonly applied: bigint;
|
|
62
|
+
readonly toPrepaid: bigint;
|
|
63
|
+
}
|
|
64
|
+
/** Reads one `Settled` log emitted by the surface, or null for any other log. */
|
|
65
|
+
export declare function decodeSettled(log: EthersV6Log, surface: Address): SettledLog | null;
|
|
66
|
+
export declare function createMonadStrategy(config: MonadStrategyConfig): PaymentStrategy;
|
|
67
|
+
export declare function indexAssets(assets: Readonly<Record<string, AssetRef>>, id: string, logger: Logger): Map<string, AssetRef>;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=monad.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monad.d.ts","sourceRoot":"","sources":["../../src/payments/monad.ts"],"names":[],"mappings":"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"}
|