@morpho-dev/router 0.1.16 → 0.1.18
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 +6 -6
- package/dist/cli.js +970 -565
- package/dist/cli.js.map +1 -1
- package/dist/index.browser.d.cts +182 -79
- package/dist/index.browser.d.ts +182 -79
- package/dist/index.browser.js +443 -235
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +444 -237
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.cts +235 -124
- package/dist/index.node.d.ts +235 -124
- package/dist/index.node.js +2361 -2023
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +2361 -2024
- package/dist/index.node.mjs.map +1 -1
- package/package.json +6 -5
package/dist/index.node.mjs
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { serve as serve$1 } from '@hono/node-server';
|
|
2
2
|
import { Hono } from 'hono';
|
|
3
3
|
import { cors } from 'hono/cors';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { z } from 'zod/v4';
|
|
5
|
+
import { createDocument } from 'zod-openapi';
|
|
6
|
+
import { maxUint256, isAddress, isHex, decodeAbiParameters, encodeAbiParameters, getAddress, keccak256, zeroAddress, hashTypedData, publicActions, parseUnits, createWalletClient, http, erc20Abi, stringify, parseEventLogs } from 'viem';
|
|
6
7
|
import { getBlock, getLogs } from 'viem/actions';
|
|
7
8
|
import { base, mainnet, anvil } from 'viem/chains';
|
|
8
9
|
import * as z6 from 'zod';
|
|
9
|
-
import { Base64 } from 'js-base64';
|
|
10
10
|
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
|
|
11
|
+
import { Base64 } from 'js-base64';
|
|
12
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
11
13
|
import { asc, desc, sql, and, eq, gt, gte, lte, inArray } from 'drizzle-orm';
|
|
12
14
|
import { pgSchema, integer, varchar, bigint, timestamp, text, boolean, numeric, index, primaryKey, uniqueIndex } from 'drizzle-orm/pg-core';
|
|
13
15
|
import path from 'path';
|
|
@@ -17,8 +19,6 @@ import { migrate } from 'drizzle-orm/node-postgres/migrator';
|
|
|
17
19
|
import { drizzle as drizzle$1 } from 'drizzle-orm/pglite';
|
|
18
20
|
import { migrate as migrate$1 } from 'drizzle-orm/pglite/migrator';
|
|
19
21
|
import { Pool } from 'pg';
|
|
20
|
-
import { z } from 'zod/v4';
|
|
21
|
-
import { createDocument } from 'zod-openapi';
|
|
22
22
|
|
|
23
23
|
var __defProp = Object.defineProperty;
|
|
24
24
|
var __export = (target, all) => {
|
|
@@ -26,9 +26,9 @@ var __export = (target, all) => {
|
|
|
26
26
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
// src/api/
|
|
30
|
-
var
|
|
31
|
-
__export(
|
|
29
|
+
// src/api/RouterApi.ts
|
|
30
|
+
var RouterApi_exports = {};
|
|
31
|
+
__export(RouterApi_exports, {
|
|
32
32
|
ChainHealth: () => ChainHealth,
|
|
33
33
|
ChainsHealthResponse: () => ChainsHealthResponse,
|
|
34
34
|
CollectorHealth: () => CollectorHealth,
|
|
@@ -43,1747 +43,1319 @@ __export(Api_exports2, {
|
|
|
43
43
|
safeParse: () => safeParse
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
// src/api/
|
|
46
|
+
// src/api/Controllers/index.ts
|
|
47
47
|
var Controllers_exports = {};
|
|
48
48
|
__export(Controllers_exports, {
|
|
49
|
+
getDocsHtml: () => getDocsHtml,
|
|
49
50
|
getHealth: () => getHealth,
|
|
50
51
|
getHealthChains: () => getHealthChains,
|
|
51
52
|
getHealthCollectors: () => getHealthCollectors,
|
|
52
53
|
getObligations: () => getObligations,
|
|
53
|
-
getOffers: () => getOffers
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// src/services/Health.ts
|
|
57
|
-
var Health_exports = {};
|
|
58
|
-
__export(Health_exports, {
|
|
59
|
-
create: () => create9
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// src/collectors/index.ts
|
|
63
|
-
var collectors_exports = {};
|
|
64
|
-
__export(collectors_exports, {
|
|
65
|
-
batch: () => batch2,
|
|
66
|
-
create: () => create2,
|
|
67
|
-
createBuilder: () => createBuilder,
|
|
68
|
-
fetchBalancesAndAllowances: () => fetchBalancesAndAllowances,
|
|
69
|
-
fetchCollateralAndDebt: () => fetchCollateralAndDebt,
|
|
70
|
-
fetchOraclePrices: () => fetchOraclePrices,
|
|
71
|
-
fetchUserVaultMarketLiquidity: () => fetchUserVaultMarketLiquidity,
|
|
72
|
-
morpho: () => morpho,
|
|
73
|
-
names: () => names,
|
|
74
|
-
run: () => run,
|
|
75
|
-
single: () => single,
|
|
76
|
-
start: () => start
|
|
54
|
+
getOffers: () => getOffers,
|
|
55
|
+
getSwaggerJson: () => getSwaggerJson
|
|
77
56
|
});
|
|
78
57
|
|
|
79
|
-
// src/
|
|
80
|
-
var
|
|
81
|
-
__export(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
58
|
+
// src/core/Abi.ts
|
|
59
|
+
var Abi_exports = {};
|
|
60
|
+
__export(Abi_exports, {
|
|
61
|
+
ERC4626: () => ERC4626,
|
|
62
|
+
MetaMorpho: () => MetaMorpho,
|
|
63
|
+
MetaMorphoFactory: () => MetaMorphoFactory,
|
|
64
|
+
Morpho: () => Morpho,
|
|
65
|
+
Oracle: () => Oracle
|
|
87
66
|
});
|
|
88
|
-
var
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
"silent"
|
|
96
|
-
];
|
|
97
|
-
function defaultLogger(minLevel, pretty) {
|
|
98
|
-
const threshold = minLevel ?? process.env.ROUTER_LOG_LEVEL ?? "info";
|
|
99
|
-
const prettyEnabled = typeof pretty === "boolean" ? pretty : String(process.env.ROUTER_LOG_PRETTY ?? "false").toLowerCase() === "true";
|
|
100
|
-
const levelIndexByName = LogLevelValues.reduce(
|
|
101
|
-
(acc, lvl, idx) => {
|
|
102
|
-
acc[lvl] = idx;
|
|
103
|
-
return acc;
|
|
104
|
-
},
|
|
105
|
-
{}
|
|
106
|
-
);
|
|
107
|
-
const isEnabled = (methodLevel) => levelIndexByName[methodLevel] >= levelIndexByName[threshold];
|
|
108
|
-
const wrap = (consoleMethod, methodLevel) => isEnabled(methodLevel) ? (entry) => {
|
|
109
|
-
if (!prettyEnabled) {
|
|
110
|
-
console[consoleMethod](stringify({ level: methodLevel, ...entry }));
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
const { msg, ...rest } = entry;
|
|
114
|
-
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
115
|
-
const level = methodLevel.toUpperCase();
|
|
116
|
-
const extras = Object.entries(rest).map(([k, v]) => `${k}=${formatValue(v)}`).join(" ");
|
|
117
|
-
const line = extras.length > 0 ? `${timestamp2} [${level}] ${msg} ${extras}` : `${timestamp2} [${level}] ${msg}`;
|
|
118
|
-
console[consoleMethod](line);
|
|
119
|
-
} : () => {
|
|
120
|
-
};
|
|
121
|
-
return {
|
|
122
|
-
trace: wrap("trace", "trace"),
|
|
123
|
-
debug: wrap("debug", "debug"),
|
|
124
|
-
info: wrap("info", "info"),
|
|
125
|
-
warn: wrap("warn", "warn"),
|
|
126
|
-
error: wrap("error", "error"),
|
|
127
|
-
fatal: wrap("error", "fatal")
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
function silentLogger() {
|
|
131
|
-
const noop = () => {
|
|
132
|
-
};
|
|
133
|
-
return { trace: noop, debug: noop, info: noop, warn: noop, error: noop, fatal: noop };
|
|
134
|
-
}
|
|
135
|
-
var loggerContext = new AsyncLocalStorage();
|
|
136
|
-
function runWithLogger(logger, fn) {
|
|
137
|
-
return loggerContext.run(logger, fn);
|
|
138
|
-
}
|
|
139
|
-
function getLogger() {
|
|
140
|
-
return loggerContext.getStore() ?? defaultLogger();
|
|
141
|
-
}
|
|
142
|
-
function formatValue(value) {
|
|
143
|
-
if (value === null || value === void 0 || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
|
|
144
|
-
return String(value);
|
|
145
|
-
}
|
|
146
|
-
if (typeof value === "string") {
|
|
147
|
-
if (value.includes(" ")) return JSON.stringify(value);
|
|
148
|
-
return value;
|
|
149
|
-
}
|
|
150
|
-
try {
|
|
151
|
-
return stringify(value);
|
|
152
|
-
} catch {
|
|
153
|
-
try {
|
|
154
|
-
return JSON.stringify(value);
|
|
155
|
-
} catch {
|
|
156
|
-
return String(value);
|
|
157
|
-
}
|
|
67
|
+
var Oracle = [
|
|
68
|
+
{
|
|
69
|
+
type: "function",
|
|
70
|
+
name: "price",
|
|
71
|
+
inputs: [],
|
|
72
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
73
|
+
stateMutability: "view"
|
|
158
74
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
batchMulticall: () => batchMulticall,
|
|
168
|
-
fromSnakeCase: () => fromSnakeCase,
|
|
169
|
-
lazy: () => lazy,
|
|
170
|
-
max: () => max,
|
|
171
|
-
min: () => min,
|
|
172
|
-
poll: () => poll,
|
|
173
|
-
retry: () => retry,
|
|
174
|
-
toSnakeCase: () => toSnakeCase,
|
|
175
|
-
wait: () => wait
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
// src/utils/BigMath.ts
|
|
179
|
-
function max(a, b) {
|
|
180
|
-
return a > b ? a : b;
|
|
181
|
-
}
|
|
182
|
-
function min(a, b) {
|
|
183
|
-
return a < b ? a : b;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// src/utils/batch.ts
|
|
187
|
-
function* batch(array2, batchSize) {
|
|
188
|
-
for (let i = 0; i < array2.length; i += batchSize) {
|
|
189
|
-
yield array2.slice(i, i + batchSize);
|
|
75
|
+
];
|
|
76
|
+
var ERC4626 = [
|
|
77
|
+
{
|
|
78
|
+
type: "function",
|
|
79
|
+
name: "asset",
|
|
80
|
+
inputs: [],
|
|
81
|
+
outputs: [{ name: "", type: "address" }],
|
|
82
|
+
stateMutability: "view"
|
|
190
83
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
} catch (err) {
|
|
200
|
-
lastErr = err;
|
|
201
|
-
if (i < attempts - 1) await new Promise((r) => setTimeout(r, delayMs));
|
|
202
|
-
}
|
|
84
|
+
];
|
|
85
|
+
var MetaMorphoFactory = [
|
|
86
|
+
{
|
|
87
|
+
type: "function",
|
|
88
|
+
name: "isMetaMorpho",
|
|
89
|
+
inputs: [{ name: "target", type: "address" }],
|
|
90
|
+
outputs: [{ name: "", type: "bool" }],
|
|
91
|
+
stateMutability: "view"
|
|
203
92
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
93
|
+
];
|
|
94
|
+
var MetaMorpho = [
|
|
95
|
+
{
|
|
96
|
+
type: "function",
|
|
97
|
+
name: "withdrawQueue",
|
|
98
|
+
inputs: [{ name: "index", type: "uint256" }],
|
|
99
|
+
outputs: [{ name: "", type: "bytes32" }],
|
|
100
|
+
stateMutability: "view"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
type: "function",
|
|
104
|
+
name: "withdrawQueueLength",
|
|
105
|
+
inputs: [],
|
|
106
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
107
|
+
stateMutability: "view"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: "function",
|
|
111
|
+
name: "maxWithdraw",
|
|
112
|
+
inputs: [{ name: "owner", type: "address" }],
|
|
113
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
114
|
+
stateMutability: "view"
|
|
222
115
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
]
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
116
|
+
];
|
|
117
|
+
var Morpho = [
|
|
118
|
+
{
|
|
119
|
+
type: "function",
|
|
120
|
+
name: "collateralOf",
|
|
121
|
+
inputs: [
|
|
122
|
+
{
|
|
123
|
+
name: "",
|
|
124
|
+
type: "address",
|
|
125
|
+
internalType: "address"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: "",
|
|
129
|
+
type: "bytes32",
|
|
130
|
+
internalType: "bytes32"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "",
|
|
134
|
+
type: "address",
|
|
135
|
+
internalType: "address"
|
|
136
|
+
}
|
|
137
|
+
],
|
|
138
|
+
outputs: [
|
|
139
|
+
{
|
|
140
|
+
name: "",
|
|
141
|
+
type: "uint256",
|
|
142
|
+
internalType: "uint256"
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
stateMutability: "view"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
type: "function",
|
|
149
|
+
name: "debtOf",
|
|
150
|
+
inputs: [
|
|
151
|
+
{
|
|
152
|
+
name: "",
|
|
153
|
+
type: "address",
|
|
154
|
+
internalType: "address"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: "",
|
|
158
|
+
type: "bytes32",
|
|
159
|
+
internalType: "bytes32"
|
|
160
|
+
}
|
|
161
|
+
],
|
|
162
|
+
outputs: [
|
|
163
|
+
{
|
|
164
|
+
name: "",
|
|
165
|
+
type: "uint256",
|
|
166
|
+
internalType: "uint256"
|
|
167
|
+
}
|
|
168
|
+
],
|
|
169
|
+
stateMutability: "view"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
type: "function",
|
|
173
|
+
name: "market",
|
|
174
|
+
inputs: [
|
|
175
|
+
{
|
|
176
|
+
name: "id",
|
|
177
|
+
type: "bytes32",
|
|
178
|
+
internalType: "Id"
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
outputs: [
|
|
182
|
+
{
|
|
183
|
+
name: "totalSupplyAssets",
|
|
184
|
+
type: "uint128",
|
|
185
|
+
internalType: "uint128"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: "totalSupplyShares",
|
|
189
|
+
type: "uint128",
|
|
190
|
+
internalType: "uint128"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: "totalBorrowAssets",
|
|
194
|
+
type: "uint128",
|
|
195
|
+
internalType: "uint128"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: "totalBorrowShares",
|
|
199
|
+
type: "uint128",
|
|
200
|
+
internalType: "uint128"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: "lastUpdate",
|
|
204
|
+
type: "uint128",
|
|
205
|
+
internalType: "uint128"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: "fee",
|
|
209
|
+
type: "uint128",
|
|
210
|
+
internalType: "uint128"
|
|
211
|
+
}
|
|
212
|
+
],
|
|
213
|
+
stateMutability: "view"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
type: "function",
|
|
217
|
+
name: "position",
|
|
218
|
+
inputs: [
|
|
219
|
+
{
|
|
220
|
+
name: "id",
|
|
221
|
+
type: "bytes32",
|
|
222
|
+
internalType: "Id"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: "user",
|
|
226
|
+
type: "address",
|
|
227
|
+
internalType: "address"
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
outputs: [
|
|
231
|
+
{
|
|
232
|
+
name: "supplyShares",
|
|
233
|
+
type: "uint256",
|
|
234
|
+
internalType: "uint256"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: "borrowShares",
|
|
238
|
+
type: "uint128",
|
|
239
|
+
internalType: "uint128"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
name: "collateral",
|
|
243
|
+
type: "uint128",
|
|
244
|
+
internalType: "uint128"
|
|
245
|
+
}
|
|
246
|
+
],
|
|
247
|
+
stateMutability: "view"
|
|
259
248
|
}
|
|
260
|
-
|
|
261
|
-
function walk(err, fn) {
|
|
262
|
-
if (fn?.(err)) return err;
|
|
263
|
-
if (err && typeof err === "object" && "cause" in err && err.cause) return walk(err.cause, fn);
|
|
264
|
-
return fn ? null : err;
|
|
265
|
-
}
|
|
249
|
+
];
|
|
266
250
|
|
|
267
|
-
// src/
|
|
268
|
-
var
|
|
269
|
-
__export(
|
|
270
|
-
|
|
271
|
-
|
|
251
|
+
// src/core/Callback.ts
|
|
252
|
+
var Callback_exports = {};
|
|
253
|
+
__export(Callback_exports, {
|
|
254
|
+
CallbackType: () => CallbackType,
|
|
255
|
+
WhitelistedCallbackAddresses: () => WhitelistedCallbackAddresses,
|
|
256
|
+
decodeBuyVaultV1Callback: () => decodeBuyVaultV1Callback,
|
|
257
|
+
decodeSellERC20Callback: () => decodeSellERC20Callback,
|
|
258
|
+
encodeBuyVaultV1Callback: () => encodeBuyVaultV1Callback,
|
|
259
|
+
encodeSellERC20Callback: () => encodeSellERC20Callback
|
|
272
260
|
});
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
261
|
+
var CallbackType = /* @__PURE__ */ ((CallbackType2) => {
|
|
262
|
+
CallbackType2["BuyWithEmptyCallback"] = "buy_with_empty_callback";
|
|
263
|
+
CallbackType2["BuyVaultV1Callback"] = "buy_vault_v1_callback";
|
|
264
|
+
CallbackType2["SellERC20Callback"] = "sell_erc20_callback";
|
|
265
|
+
return CallbackType2;
|
|
266
|
+
})(CallbackType || {});
|
|
267
|
+
var WhitelistedCallbackAddresses = {
|
|
268
|
+
["buy_with_empty_callback" /* BuyWithEmptyCallback */]: [],
|
|
269
|
+
["buy_vault_v1_callback" /* BuyVaultV1Callback */]: [
|
|
270
|
+
"0x3333333333333333333333333333333333333333",
|
|
271
|
+
"0x4444444444444444444444444444444444444444"
|
|
272
|
+
// @TODO: update once deployed and add mapping per chain if needed
|
|
273
|
+
].map((address) => address.toLowerCase()),
|
|
274
|
+
["sell_erc20_callback" /* SellERC20Callback */]: [
|
|
275
|
+
"0x1111111111111111111111111111111111111111",
|
|
276
|
+
"0x2222222222222222222222222222222222222222"
|
|
277
|
+
// @TODO: update once deployed and add mapping per chain if needed
|
|
278
|
+
].map((address) => address.toLowerCase())
|
|
279
|
+
};
|
|
280
|
+
function decodeBuyVaultV1Callback(data) {
|
|
281
|
+
if (!data || data === "0x") throw new Error("Empty callback data");
|
|
282
|
+
try {
|
|
283
|
+
const [vaults, amounts] = decodeAbiParameters(
|
|
284
|
+
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
285
|
+
data
|
|
286
|
+
);
|
|
287
|
+
if (vaults.length !== amounts.length) {
|
|
288
|
+
throw new Error("Mismatched array lengths");
|
|
289
|
+
}
|
|
290
|
+
return vaults.map((v, i) => ({ vault: v, amount: amounts[i] }));
|
|
291
|
+
} catch (_) {
|
|
292
|
+
throw new Error("Invalid BuyVaultV1Callback callback data");
|
|
293
|
+
}
|
|
281
294
|
}
|
|
282
|
-
function
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
295
|
+
function decodeSellERC20Callback(data) {
|
|
296
|
+
if (!data || data === "0x") throw new Error("Empty callback data");
|
|
297
|
+
try {
|
|
298
|
+
const [collaterals, amounts] = decodeAbiParameters(
|
|
299
|
+
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
300
|
+
data
|
|
301
|
+
);
|
|
302
|
+
if (collaterals.length !== amounts.length) {
|
|
303
|
+
throw new Error("Mismatched array lengths");
|
|
304
|
+
}
|
|
305
|
+
return collaterals.map((c, i) => ({ collateral: c, amount: amounts[i] }));
|
|
306
|
+
} catch (_) {
|
|
307
|
+
throw new Error("Invalid SellERC20Callback callback data");
|
|
308
|
+
}
|
|
288
309
|
}
|
|
289
|
-
function
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
(acc, [key, value]) => {
|
|
294
|
-
const newKey = fnKey(key);
|
|
295
|
-
acc[newKey] = typeof value === "object" && value !== null ? processObject(value, fnKey, fnValue) : fnValue(value);
|
|
296
|
-
return acc;
|
|
297
|
-
},
|
|
298
|
-
{}
|
|
310
|
+
function encodeBuyVaultV1Callback(parameters) {
|
|
311
|
+
return encodeAbiParameters(
|
|
312
|
+
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
313
|
+
[parameters.vaults, parameters.amounts]
|
|
299
314
|
);
|
|
300
315
|
}
|
|
301
|
-
function
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
for (const [k, v] of Object.entries(value)) {
|
|
307
|
-
out[k] = stringifyBigint(v);
|
|
308
|
-
}
|
|
309
|
-
return out;
|
|
310
|
-
}
|
|
311
|
-
return value;
|
|
316
|
+
function encodeSellERC20Callback(parameters) {
|
|
317
|
+
return encodeAbiParameters(
|
|
318
|
+
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
319
|
+
[parameters.collaterals, parameters.amounts]
|
|
320
|
+
);
|
|
312
321
|
}
|
|
313
322
|
|
|
314
|
-
// src/
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const stop = () => {
|
|
330
|
-
active = false;
|
|
331
|
-
unpoll?.();
|
|
332
|
-
resolveNext?.();
|
|
333
|
-
resolveNext = null;
|
|
334
|
-
};
|
|
335
|
-
unpoll = pollFn(emit, { stop });
|
|
336
|
-
try {
|
|
337
|
-
while (active) {
|
|
338
|
-
if (queue.length === 0) await wait2();
|
|
339
|
-
while (queue.length > 0 && active) yield queue.shift();
|
|
340
|
-
}
|
|
341
|
-
} finally {
|
|
342
|
-
stop();
|
|
343
|
-
}
|
|
344
|
-
}();
|
|
345
|
-
}
|
|
323
|
+
// src/core/Chain.ts
|
|
324
|
+
var Chain_exports = {};
|
|
325
|
+
__export(Chain_exports, {
|
|
326
|
+
ChainId: () => ChainId,
|
|
327
|
+
InvalidBatchSizeError: () => InvalidBatchSizeError,
|
|
328
|
+
InvalidBlockRangeError: () => InvalidBlockRangeError,
|
|
329
|
+
InvalidBlockWindowError: () => InvalidBlockWindowError,
|
|
330
|
+
MissingBlockNumberError: () => MissingBlockNumberError,
|
|
331
|
+
chainIds: () => chainIds,
|
|
332
|
+
chainNames: () => chainNames,
|
|
333
|
+
chains: () => chains,
|
|
334
|
+
getChain: () => getChain,
|
|
335
|
+
getWhitelistedChains: () => getWhitelistedChains,
|
|
336
|
+
streamLogs: () => streamLogs
|
|
337
|
+
});
|
|
346
338
|
|
|
347
|
-
// src/utils/
|
|
348
|
-
|
|
349
|
-
return
|
|
339
|
+
// src/utils/BigMath.ts
|
|
340
|
+
function max(a, b) {
|
|
341
|
+
return a > b ? a : b;
|
|
342
|
+
}
|
|
343
|
+
function min(a, b) {
|
|
344
|
+
return a < b ? a : b;
|
|
350
345
|
}
|
|
351
346
|
|
|
352
|
-
// src/utils/
|
|
353
|
-
function
|
|
354
|
-
let
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
await wait(interval);
|
|
358
|
-
const poll2 = async () => {
|
|
359
|
-
if (!active) return;
|
|
360
|
-
await fn({ unpoll: unwatch });
|
|
361
|
-
await wait(interval);
|
|
362
|
-
poll2();
|
|
363
|
-
};
|
|
364
|
-
poll2();
|
|
365
|
-
};
|
|
366
|
-
watch2();
|
|
367
|
-
return unwatch;
|
|
347
|
+
// src/utils/batch.ts
|
|
348
|
+
function* batch(array2, batchSize) {
|
|
349
|
+
for (let i = 0; i < array2.length; i += batchSize) {
|
|
350
|
+
yield array2.slice(i, i + batchSize);
|
|
351
|
+
}
|
|
368
352
|
}
|
|
369
353
|
|
|
370
|
-
// src/utils/
|
|
371
|
-
var
|
|
372
|
-
__export(
|
|
373
|
-
|
|
374
|
-
now: () => now
|
|
354
|
+
// src/utils/Errors.ts
|
|
355
|
+
var Errors_exports = {};
|
|
356
|
+
__export(Errors_exports, {
|
|
357
|
+
BaseError: () => BaseError
|
|
375
358
|
});
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
359
|
+
var BaseError = class _BaseError extends Error {
|
|
360
|
+
details;
|
|
361
|
+
shortMessage;
|
|
362
|
+
cause;
|
|
363
|
+
name = "BaseError";
|
|
364
|
+
constructor(shortMessage, options = {}) {
|
|
365
|
+
const details = (() => {
|
|
366
|
+
if (options.cause instanceof _BaseError) {
|
|
367
|
+
if (options.cause.details) return options.cause.details;
|
|
368
|
+
if (options.cause.shortMessage) return options.cause.shortMessage;
|
|
369
|
+
}
|
|
370
|
+
if (options.cause && "details" in options.cause && typeof options.cause.details === "string")
|
|
371
|
+
return options.cause.details;
|
|
372
|
+
if (options.cause?.message) return options.cause.message;
|
|
373
|
+
return options.details;
|
|
374
|
+
})();
|
|
375
|
+
const message = [
|
|
376
|
+
shortMessage || "An error occurred.",
|
|
377
|
+
...options.metaMessages ? ["", ...options.metaMessages] : [],
|
|
378
|
+
...details ? ["", details ? `Details: ${details}` : void 0] : []
|
|
379
|
+
].filter((x) => typeof x === "string").join("\n");
|
|
380
|
+
super(message, options.cause ? { cause: options.cause } : void 0);
|
|
381
|
+
this.cause = options.cause;
|
|
382
|
+
this.details = details;
|
|
383
|
+
this.shortMessage = shortMessage;
|
|
384
|
+
}
|
|
385
|
+
walk(fn) {
|
|
386
|
+
return walk(this, fn);
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
function walk(err, fn) {
|
|
390
|
+
if (fn?.(err)) return err;
|
|
391
|
+
if (err && typeof err === "object" && "cause" in err && err.cause) return walk(err.cause, fn);
|
|
392
|
+
return fn ? null : err;
|
|
381
393
|
}
|
|
382
394
|
|
|
383
|
-
// src/
|
|
384
|
-
|
|
385
|
-
|
|
395
|
+
// src/core/Chain.ts
|
|
396
|
+
var chainNames = ["ethereum", "base", "ethereum-virtual-testnet", "anvil"];
|
|
397
|
+
var ChainId = {
|
|
398
|
+
ETHEREUM: BigInt(mainnet.id),
|
|
399
|
+
BASE: BigInt(base.id),
|
|
400
|
+
"ETHEREUM-VIRTUAL-TESTNET": 109111114n,
|
|
401
|
+
ANVIL: 505050505n
|
|
402
|
+
// random id to not clash with other chains
|
|
403
|
+
};
|
|
404
|
+
var chainIds = new Set(Object.values(ChainId));
|
|
405
|
+
var chainNameLookup = new Map(Object.entries(ChainId).map(([key, value]) => [value, key]));
|
|
406
|
+
function getChain(chainId) {
|
|
407
|
+
const chainName = chainNameLookup.get(chainId)?.toLowerCase();
|
|
408
|
+
if (!chainName) {
|
|
409
|
+
return void 0;
|
|
410
|
+
}
|
|
411
|
+
return chains[chainName];
|
|
412
|
+
}
|
|
413
|
+
var getWhitelistedChains = () => {
|
|
414
|
+
return [chains.ethereum, chains.base, chains["ethereum-virtual-testnet"], chains.anvil];
|
|
415
|
+
};
|
|
416
|
+
var chains = {
|
|
417
|
+
ethereum: {
|
|
418
|
+
...mainnet,
|
|
419
|
+
id: ChainId.ETHEREUM,
|
|
420
|
+
name: "ethereum",
|
|
421
|
+
whitelistedAssets: new Set(
|
|
422
|
+
[
|
|
423
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
424
|
+
// USDC
|
|
425
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
426
|
+
// DAI
|
|
427
|
+
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
428
|
+
// WETH
|
|
429
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
430
|
+
// WBTC
|
|
431
|
+
].map((address) => address.toLowerCase())
|
|
432
|
+
),
|
|
433
|
+
morpho: "0x0000000000000000000000000000000000000000",
|
|
434
|
+
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
435
|
+
mempool: {
|
|
436
|
+
address: "0x0000000000000000000000000000000000000000",
|
|
437
|
+
deploymentBlock: 23347674,
|
|
438
|
+
reindexBuffer: 10
|
|
439
|
+
},
|
|
440
|
+
vaultV1Factory: {
|
|
441
|
+
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
442
|
+
"v1.1": "0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
base: {
|
|
446
|
+
...base,
|
|
447
|
+
id: ChainId.BASE,
|
|
448
|
+
name: "base",
|
|
449
|
+
whitelistedAssets: new Set(
|
|
450
|
+
[
|
|
451
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
452
|
+
// USDC
|
|
453
|
+
"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
|
|
454
|
+
// DAI
|
|
455
|
+
"0x4200000000000000000000000000000000000006",
|
|
456
|
+
// WETH
|
|
457
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
458
|
+
// WBTC
|
|
459
|
+
].map((address) => address.toLowerCase())
|
|
460
|
+
),
|
|
461
|
+
morpho: "0x0000000000000000000000000000000000000000",
|
|
462
|
+
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
463
|
+
mempool: {
|
|
464
|
+
address: "0x0000000000000000000000000000000000000000",
|
|
465
|
+
deploymentBlock: 35449942,
|
|
466
|
+
reindexBuffer: 10
|
|
467
|
+
},
|
|
468
|
+
vaultV1Factory: {
|
|
469
|
+
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
470
|
+
"v1.1": "0xFf62A7c278C62eD665133147129245053Bbf5918"
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
"ethereum-virtual-testnet": {
|
|
474
|
+
...mainnet,
|
|
475
|
+
id: ChainId["ETHEREUM-VIRTUAL-TESTNET"],
|
|
476
|
+
name: "ethereum-virtual-testnet",
|
|
477
|
+
whitelistedAssets: new Set(
|
|
478
|
+
[
|
|
479
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
480
|
+
// USDC
|
|
481
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
482
|
+
// DAI
|
|
483
|
+
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
484
|
+
// WETH
|
|
485
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
486
|
+
// WBTC
|
|
487
|
+
].map((address) => address.toLowerCase())
|
|
488
|
+
),
|
|
489
|
+
morpho: "0x11a002d45db720ed47a80d2f3489cba5b833eaf5",
|
|
490
|
+
// @TODO: This is mock Consumed contract, update with Terms once stable
|
|
491
|
+
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
492
|
+
mempool: {
|
|
493
|
+
address: "0x5b06224f736a57635b5bcb50b8ef178b189107cb",
|
|
494
|
+
deploymentBlock: 23224302,
|
|
495
|
+
reindexBuffer: 10
|
|
496
|
+
},
|
|
497
|
+
vaultV1Factory: {
|
|
498
|
+
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
499
|
+
"v1.1": "0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
anvil: {
|
|
503
|
+
...anvil,
|
|
504
|
+
id: ChainId.ANVIL,
|
|
505
|
+
name: "anvil",
|
|
506
|
+
whitelistedAssets: new Set(
|
|
507
|
+
[
|
|
508
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
509
|
+
// USDC
|
|
510
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
511
|
+
// DAI
|
|
512
|
+
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
513
|
+
// WETH
|
|
514
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
515
|
+
// WBTC
|
|
516
|
+
].map((address) => address.toLowerCase())
|
|
517
|
+
),
|
|
518
|
+
morpho: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
|
|
519
|
+
morphoBlue: "0x0000000000000000000000000000000000000000",
|
|
520
|
+
// Set dynamically in tests
|
|
521
|
+
mempool: {
|
|
522
|
+
address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
|
|
523
|
+
deploymentBlock: 23223727,
|
|
524
|
+
reindexBuffer: 10
|
|
525
|
+
},
|
|
526
|
+
vaultV1Factory: {
|
|
527
|
+
"v1.0": "0x0000000000000000000000000000000000000000",
|
|
528
|
+
"v1.1": "0x0000000000000000000000000000000000000000"
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
var MAX_BATCH_SIZE = 1e4;
|
|
533
|
+
var DEFAULT_BATCH_SIZE = 2500;
|
|
534
|
+
var MAX_BLOCK_WINDOW = 2e3;
|
|
535
|
+
var DEFAULT_BLOCK_WINDOW = 500;
|
|
536
|
+
async function* streamLogs(parameters) {
|
|
386
537
|
const {
|
|
387
538
|
client,
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
539
|
+
contractAddress,
|
|
540
|
+
event,
|
|
541
|
+
blockNumberGte,
|
|
542
|
+
blockNumberLte,
|
|
543
|
+
order = "desc",
|
|
544
|
+
options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = DEFAULT_BLOCK_WINDOW } = {}
|
|
391
545
|
} = parameters;
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const
|
|
396
|
-
let
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
max_block_number: maxBlockNumber
|
|
416
|
-
});
|
|
417
|
-
isMaxBlockNumberReached = true;
|
|
418
|
-
await chainStore.saveBlockNumber({
|
|
419
|
-
chainId: chain.id,
|
|
420
|
-
blockNumber: maxBlockNumber,
|
|
421
|
-
epoch: epoch + 1n
|
|
422
|
-
});
|
|
423
|
-
await Promise.all(
|
|
424
|
-
names.map(
|
|
425
|
-
async (collectorName) => collectorStore.saveBlockNumber({
|
|
426
|
-
collectorName,
|
|
427
|
-
chainId: chain.id,
|
|
428
|
-
blockNumber: maxBlockNumber,
|
|
429
|
-
epoch: epoch + 1n
|
|
430
|
-
})
|
|
431
|
-
)
|
|
432
|
-
);
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
finalizedBlock = await fetchFinalizedBlock({
|
|
436
|
-
tick,
|
|
437
|
-
client,
|
|
438
|
-
chain,
|
|
439
|
-
logger,
|
|
440
|
-
collector,
|
|
441
|
-
unfinalizedBlocks,
|
|
442
|
-
previousFinalizedBlock: finalizedBlock
|
|
443
|
-
});
|
|
444
|
-
tick++;
|
|
445
|
-
let {
|
|
446
|
-
block: returnedBlock,
|
|
447
|
-
didReorgHappened,
|
|
448
|
-
unfinalizedBlocks: newUnfinalizedBlocks
|
|
449
|
-
} = await reconcile({
|
|
450
|
-
client,
|
|
451
|
-
block: head,
|
|
452
|
-
unfinalizedBlocks,
|
|
453
|
-
finalizedBlock,
|
|
454
|
-
logger,
|
|
455
|
-
collector,
|
|
456
|
-
chain,
|
|
457
|
-
maxBatchSize
|
|
458
|
-
});
|
|
459
|
-
unfinalizedBlocks = newUnfinalizedBlocks;
|
|
460
|
-
const blockNumber = Number(returnedBlock.number);
|
|
461
|
-
didReorgHappened = didReorgHappened || blockNumber < latestSavedBlockNumber;
|
|
462
|
-
await chainStore.saveBlockNumber({
|
|
463
|
-
chainId: chain.id,
|
|
464
|
-
blockNumber,
|
|
465
|
-
epoch: didReorgHappened ? epoch + 1n : epoch
|
|
466
|
-
});
|
|
467
|
-
if (didReorgHappened) {
|
|
468
|
-
await Promise.all(
|
|
469
|
-
names.map(
|
|
470
|
-
async (collectorName) => collectorStore.saveBlockNumber({
|
|
471
|
-
collectorName,
|
|
472
|
-
chainId: chain.id,
|
|
473
|
-
blockNumber,
|
|
474
|
-
epoch: epoch + 1n
|
|
475
|
-
})
|
|
476
|
-
)
|
|
477
|
-
);
|
|
478
|
-
}
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
var commonAncestor = (block, unfinalizedBlocks) => {
|
|
484
|
-
const parent = unfinalizedBlocks.find((b) => b.hash === block.parentHash);
|
|
485
|
-
if (parent) return parent;
|
|
486
|
-
return null;
|
|
487
|
-
};
|
|
488
|
-
var fetchFinalizedBlock = async (parameters) => {
|
|
489
|
-
let { tick, client, chain, logger, collector, unfinalizedBlocks, previousFinalizedBlock } = parameters;
|
|
490
|
-
let finalizedBlock = previousFinalizedBlock;
|
|
491
|
-
if (tick % 20 === 0 || previousFinalizedBlock === null) {
|
|
492
|
-
finalizedBlock = await client.getBlock({
|
|
493
|
-
blockTag: "finalized",
|
|
494
|
-
includeTransactions: false
|
|
546
|
+
if (maxBatchSize > MAX_BATCH_SIZE) throw new InvalidBatchSizeError(maxBatchSize);
|
|
547
|
+
if (blockWindow > MAX_BLOCK_WINDOW) throw new InvalidBlockWindowError(blockWindow);
|
|
548
|
+
if (order === "asc" && blockNumberGte === void 0) throw new MissingBlockNumberError();
|
|
549
|
+
const latestBlock = (await getBlock(client, { blockTag: "latest", includeTransactions: false })).number;
|
|
550
|
+
let toBlock = 0n;
|
|
551
|
+
if (order === "asc")
|
|
552
|
+
toBlock = min(BigInt(blockNumberGte) + BigInt(blockWindow), latestBlock);
|
|
553
|
+
if (order === "desc")
|
|
554
|
+
toBlock = blockNumberLte === void 0 ? latestBlock : min(BigInt(blockNumberLte), latestBlock);
|
|
555
|
+
let fromBlock = 0n;
|
|
556
|
+
if (order === "asc") fromBlock = min(BigInt(blockNumberGte), latestBlock);
|
|
557
|
+
if (order === "desc")
|
|
558
|
+
fromBlock = max(BigInt(blockNumberGte || toBlock - BigInt(blockWindow)), 0n);
|
|
559
|
+
if (order === "asc") toBlock = min(toBlock, fromBlock + BigInt(blockWindow));
|
|
560
|
+
if (order === "desc") fromBlock = max(fromBlock, toBlock - BigInt(blockWindow));
|
|
561
|
+
if (fromBlock > toBlock) throw new InvalidBlockRangeError(fromBlock, toBlock);
|
|
562
|
+
let streaming = true;
|
|
563
|
+
while (streaming) {
|
|
564
|
+
const logs = await getLogs(client, {
|
|
565
|
+
address: contractAddress,
|
|
566
|
+
event,
|
|
567
|
+
fromBlock,
|
|
568
|
+
toBlock
|
|
495
569
|
});
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
570
|
+
logs.sort((a, b) => {
|
|
571
|
+
if (a.blockNumber !== b.blockNumber)
|
|
572
|
+
return order === "asc" ? Number(a.blockNumber - b.blockNumber) : Number(b.blockNumber - a.blockNumber);
|
|
573
|
+
if (a.transactionIndex !== b.transactionIndex)
|
|
574
|
+
return order === "asc" ? a.transactionIndex - b.transactionIndex : b.transactionIndex - a.transactionIndex;
|
|
575
|
+
return order === "asc" ? a.logIndex - b.logIndex : b.logIndex - a.logIndex;
|
|
576
|
+
});
|
|
577
|
+
for (const logBatch of batch(logs, maxBatchSize)) {
|
|
578
|
+
if (logBatch.length === 0) break;
|
|
579
|
+
yield {
|
|
580
|
+
logs: logBatch,
|
|
581
|
+
blockNumber: logBatch.length === maxBatchSize ? (
|
|
582
|
+
// if the batch is full, return the last block number, block numbers are always sorted
|
|
583
|
+
Number(logBatch[logBatch.length - 1]?.blockNumber)
|
|
584
|
+
) : (
|
|
585
|
+
// if the batch is not full, return `toBlock` or `fromBlock` to indicate until which block the logs were fetched
|
|
586
|
+
order === "asc" ? Number(toBlock) : Number(fromBlock)
|
|
587
|
+
)
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
streaming = order === "asc" ? toBlock < (blockNumberLte || latestBlock) : fromBlock > (blockNumberGte || 0n);
|
|
591
|
+
if (order === "asc") {
|
|
592
|
+
fromBlock = min(BigInt(toBlock) + 1n, latestBlock);
|
|
593
|
+
toBlock = min(fromBlock + BigInt(blockWindow), latestBlock);
|
|
594
|
+
}
|
|
595
|
+
if (order === "desc") {
|
|
596
|
+
const lowerBound = BigInt(blockNumberGte || 0);
|
|
597
|
+
const windowSize = BigInt(blockWindow);
|
|
598
|
+
const nextToBlock = max(fromBlock - 1n, lowerBound);
|
|
599
|
+
const nextFromBlock = max(nextToBlock - windowSize, lowerBound);
|
|
600
|
+
toBlock = nextToBlock;
|
|
601
|
+
fromBlock = nextFromBlock;
|
|
500
602
|
}
|
|
501
|
-
unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number >= finalizedBlock.number);
|
|
502
603
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
604
|
+
yield { logs: [], blockNumber: order === "asc" ? Number(toBlock) : Number(fromBlock) };
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
var InvalidBlockRangeError = class extends BaseError {
|
|
608
|
+
name = "Chain.InvalidBlockRangeError";
|
|
609
|
+
constructor(fromBlock, toBlock) {
|
|
610
|
+
super(
|
|
611
|
+
`Invalid block range while streaming data from chain. From block ${fromBlock} to block ${toBlock}.`
|
|
612
|
+
);
|
|
507
613
|
}
|
|
508
|
-
return {
|
|
509
|
-
hash: finalizedBlock.hash,
|
|
510
|
-
number: finalizedBlock.number,
|
|
511
|
-
parentHash: finalizedBlock.parentHash
|
|
512
|
-
};
|
|
513
614
|
};
|
|
514
|
-
var
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
if (latestBlock === void 0) {
|
|
520
|
-
const newBlock2 = {
|
|
521
|
-
hash: block.hash,
|
|
522
|
-
number: block.number,
|
|
523
|
-
parentHash: block.parentHash
|
|
524
|
-
};
|
|
525
|
-
unfinalizedBlocks.push(newBlock2);
|
|
526
|
-
return { block: newBlock2, didReorgHappened: false, unfinalizedBlocks };
|
|
527
|
-
}
|
|
528
|
-
if (latestBlock.hash === block.hash)
|
|
529
|
-
return { block: latestBlock, didReorgHappened: false, unfinalizedBlocks };
|
|
530
|
-
if (latestBlock.number >= block.number) {
|
|
531
|
-
const ancestor = commonAncestor(block, unfinalizedBlocks) || finalizedBlock;
|
|
532
|
-
logger.info({
|
|
533
|
-
msg: `Reorg detected`,
|
|
534
|
-
collector,
|
|
535
|
-
chain_id: chain.id,
|
|
536
|
-
ancestor: ancestor.number,
|
|
537
|
-
block_range: [latestBlock.number, block.number]
|
|
538
|
-
});
|
|
539
|
-
unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number <= ancestor.number);
|
|
540
|
-
return { block: ancestor, didReorgHappened: true, unfinalizedBlocks };
|
|
541
|
-
}
|
|
542
|
-
if (latestBlock.number + 1n < block.number) {
|
|
543
|
-
logger.debug({
|
|
544
|
-
collector,
|
|
545
|
-
chain_id: chain.id,
|
|
546
|
-
block_range: [latestBlock.number, block.number],
|
|
547
|
-
msg: `Missing blocks`
|
|
548
|
-
});
|
|
549
|
-
const missingBlockNumbers = (() => {
|
|
550
|
-
const missingBlockNumbers2 = [];
|
|
551
|
-
let start2 = latestBlock.number + 1n;
|
|
552
|
-
const threshold = latestBlock.number + BigInt(maxBatchSize) > block.number ? block.number : latestBlock.number + BigInt(maxBatchSize);
|
|
553
|
-
while (start2 < threshold) {
|
|
554
|
-
missingBlockNumbers2.push(start2);
|
|
555
|
-
start2 = start2 + 1n;
|
|
556
|
-
}
|
|
557
|
-
return missingBlockNumbers2;
|
|
558
|
-
})();
|
|
559
|
-
const missingBlocks = await Promise.all(
|
|
560
|
-
missingBlockNumbers.map(
|
|
561
|
-
(blockNumber) => retry(async () => await client.getBlock({ blockNumber, includeTransactions: false }))
|
|
562
|
-
)
|
|
615
|
+
var InvalidBlockWindowError = class extends BaseError {
|
|
616
|
+
name = "Chain.InvalidBlockWindowError";
|
|
617
|
+
constructor(blockWindow) {
|
|
618
|
+
super(
|
|
619
|
+
`Invalid block window while streaming data from chain. Maximum is ${MAX_BLOCK_WINDOW}. Got ${blockWindow}.`
|
|
563
620
|
);
|
|
564
|
-
for (const missingBlock of missingBlocks) {
|
|
565
|
-
const { block: returnedBlock, didReorgHappened } = await reconcile({
|
|
566
|
-
client,
|
|
567
|
-
block: missingBlock,
|
|
568
|
-
unfinalizedBlocks,
|
|
569
|
-
finalizedBlock,
|
|
570
|
-
logger,
|
|
571
|
-
collector,
|
|
572
|
-
chain,
|
|
573
|
-
maxBatchSize
|
|
574
|
-
});
|
|
575
|
-
if (returnedBlock.number !== missingBlock.number)
|
|
576
|
-
return { block: returnedBlock, didReorgHappened, unfinalizedBlocks };
|
|
577
|
-
}
|
|
578
|
-
return reconcile({
|
|
579
|
-
client,
|
|
580
|
-
block,
|
|
581
|
-
unfinalizedBlocks,
|
|
582
|
-
finalizedBlock,
|
|
583
|
-
logger,
|
|
584
|
-
collector,
|
|
585
|
-
chain,
|
|
586
|
-
maxBatchSize
|
|
587
|
-
});
|
|
588
621
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
622
|
+
};
|
|
623
|
+
var InvalidBatchSizeError = class extends BaseError {
|
|
624
|
+
name = "Chain.InvalidBatchSizeError";
|
|
625
|
+
constructor(maxBatchSize) {
|
|
626
|
+
super(
|
|
627
|
+
`Invalid batch size while streaming data from chain. Maximum is ${MAX_BATCH_SIZE}. Got ${maxBatchSize}.`
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
var MissingBlockNumberError = class extends BaseError {
|
|
632
|
+
name = "Chain.MissingBlockNumberError";
|
|
633
|
+
constructor() {
|
|
634
|
+
super("Missing block number when streaming data from chain in ascending order.");
|
|
600
635
|
}
|
|
601
|
-
const newBlock = {
|
|
602
|
-
hash: block.hash,
|
|
603
|
-
number: block.number,
|
|
604
|
-
parentHash: block.parentHash
|
|
605
|
-
};
|
|
606
|
-
unfinalizedBlocks.push(newBlock);
|
|
607
|
-
return { block: newBlock, didReorgHappened: false, unfinalizedBlocks };
|
|
608
636
|
};
|
|
609
637
|
|
|
610
|
-
// src/
|
|
611
|
-
var
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
"sell_erc20_callback_liquidity"
|
|
617
|
-
];
|
|
618
|
-
function create2({
|
|
619
|
-
name,
|
|
620
|
-
collect,
|
|
621
|
-
client,
|
|
622
|
-
chain,
|
|
623
|
-
withTransaction,
|
|
624
|
-
collectorStore,
|
|
625
|
-
options
|
|
626
|
-
}) {
|
|
627
|
-
const admin = create({
|
|
628
|
-
client,
|
|
629
|
-
chain,
|
|
630
|
-
withTransaction,
|
|
631
|
-
options
|
|
632
|
-
});
|
|
633
|
-
return {
|
|
634
|
-
name,
|
|
635
|
-
chain,
|
|
636
|
-
collect: lazy((emit) => {
|
|
637
|
-
const collector = name;
|
|
638
|
-
const logger = getLogger();
|
|
639
|
-
logger.info({
|
|
640
|
-
msg: `Collector started`,
|
|
641
|
-
collector,
|
|
642
|
-
chain_id: chain.id,
|
|
643
|
-
interval: options.interval
|
|
644
|
-
});
|
|
645
|
-
return poll(
|
|
646
|
-
async () => {
|
|
647
|
-
let { blockNumber: lastBlockNumber, epoch } = await collectorStore.getBlockNumber({
|
|
648
|
-
collectorName: name,
|
|
649
|
-
chainId: chain.id
|
|
650
|
-
});
|
|
651
|
-
await admin.syncBlock();
|
|
652
|
-
lastBlockNumber = await collect({
|
|
653
|
-
chain,
|
|
654
|
-
client,
|
|
655
|
-
collector: name,
|
|
656
|
-
epoch,
|
|
657
|
-
lastBlockNumber,
|
|
658
|
-
withTransaction
|
|
659
|
-
});
|
|
660
|
-
emit(lastBlockNumber);
|
|
661
|
-
},
|
|
662
|
-
{ interval: options.interval }
|
|
663
|
-
);
|
|
664
|
-
})
|
|
665
|
-
};
|
|
666
|
-
}
|
|
667
|
-
function start(collector) {
|
|
668
|
-
let stopped = false;
|
|
669
|
-
const it = collector.collect();
|
|
670
|
-
(async () => {
|
|
671
|
-
while (!stopped) await it.next();
|
|
672
|
-
await it.return();
|
|
673
|
-
})();
|
|
674
|
-
return () => {
|
|
675
|
-
stopped = true;
|
|
676
|
-
};
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
// src/mempool/index.ts
|
|
680
|
-
var mempool_exports = {};
|
|
681
|
-
__export(mempool_exports, {
|
|
682
|
-
ChainIdMismatchError: () => ChainIdMismatchError,
|
|
683
|
-
ViemClientError: () => ViemClientError,
|
|
684
|
-
WalletAccountNotSetError: () => WalletAccountNotSetError,
|
|
685
|
-
add: () => add,
|
|
686
|
-
connect: () => connect,
|
|
687
|
-
from: () => from6,
|
|
688
|
-
get: () => get,
|
|
689
|
-
watch: () => watch
|
|
638
|
+
// src/core/Collateral.ts
|
|
639
|
+
var Collateral_exports = {};
|
|
640
|
+
__export(Collateral_exports, {
|
|
641
|
+
CollateralSchema: () => CollateralSchema,
|
|
642
|
+
CollateralsSchema: () => CollateralsSchema,
|
|
643
|
+
from: () => from2
|
|
690
644
|
});
|
|
645
|
+
var transformHex = (val, ctx) => {
|
|
646
|
+
if (isHex(val)) return val;
|
|
647
|
+
ctx.addIssue({
|
|
648
|
+
code: "invalid_format",
|
|
649
|
+
input: val,
|
|
650
|
+
format: "hex",
|
|
651
|
+
error: "not a hex"
|
|
652
|
+
});
|
|
653
|
+
return z6.NEVER;
|
|
654
|
+
};
|
|
655
|
+
var transformAddress = (val, ctx) => {
|
|
656
|
+
if (isAddress(val.toLowerCase())) return val.toLowerCase();
|
|
657
|
+
ctx.addIssue({
|
|
658
|
+
code: "invalid_format",
|
|
659
|
+
input: val,
|
|
660
|
+
format: "address",
|
|
661
|
+
error: "not a valid address"
|
|
662
|
+
});
|
|
663
|
+
return z6.NEVER;
|
|
664
|
+
};
|
|
691
665
|
|
|
692
|
-
// src/core/
|
|
693
|
-
var
|
|
694
|
-
__export(
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
666
|
+
// src/core/LLTV.ts
|
|
667
|
+
var LLTV_exports = {};
|
|
668
|
+
__export(LLTV_exports, {
|
|
669
|
+
InvalidLLTVError: () => InvalidLLTVError,
|
|
670
|
+
InvalidOptionError: () => InvalidOptionError,
|
|
671
|
+
LLTVSchema: () => LLTVSchema,
|
|
672
|
+
Options: () => Options,
|
|
673
|
+
from: () => from
|
|
700
674
|
});
|
|
701
|
-
var
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
675
|
+
var Options = [0.385, 0.5, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965, 0.98];
|
|
676
|
+
var LLTV_SCALED = Options.map((lltv) => BigInt(lltv * 10 ** 18));
|
|
677
|
+
function from(lltv) {
|
|
678
|
+
if (typeof lltv === "bigint" && !LLTV_SCALED.includes(lltv)) throw new InvalidLLTVError(lltv);
|
|
679
|
+
if (typeof lltv === "bigint") return lltv;
|
|
680
|
+
if (typeof lltv === "number" && !Options.includes(lltv)) throw new InvalidOptionError(lltv);
|
|
681
|
+
return BigInt(lltv * 10 ** 18);
|
|
682
|
+
}
|
|
683
|
+
var InvalidOptionError = class extends BaseError {
|
|
684
|
+
name = "LLTV.InvalidOptionError";
|
|
685
|
+
constructor(input) {
|
|
686
|
+
super(
|
|
687
|
+
`Invalid LLTV option. Input: "${input}". Accepted values are: ${Options.map(
|
|
688
|
+
(option) => `"${option}"`
|
|
689
|
+
).join(", ")}.`
|
|
690
|
+
);
|
|
708
691
|
}
|
|
709
|
-
|
|
710
|
-
var
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
692
|
+
};
|
|
693
|
+
var InvalidLLTVError = class extends BaseError {
|
|
694
|
+
name = "LLTV.InvalidLLTVError";
|
|
695
|
+
constructor(input) {
|
|
696
|
+
super(
|
|
697
|
+
`Invalid LLTV. Input: "${input}". Accepted values are: ${LLTV_SCALED.map(
|
|
698
|
+
(option) => `"${option}"`
|
|
699
|
+
).join(", ")}.`
|
|
700
|
+
);
|
|
717
701
|
}
|
|
718
|
-
|
|
719
|
-
var
|
|
702
|
+
};
|
|
703
|
+
var LLTVSchema = z6.bigint({ coerce: true }).refine(
|
|
704
|
+
(lltv) => {
|
|
705
|
+
try {
|
|
706
|
+
from(lltv);
|
|
707
|
+
return true;
|
|
708
|
+
} catch (_) {
|
|
709
|
+
return false;
|
|
710
|
+
}
|
|
711
|
+
},
|
|
720
712
|
{
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
outputs: [{ name: "", type: "bool" }],
|
|
725
|
-
stateMutability: "view"
|
|
713
|
+
error: () => {
|
|
714
|
+
return "Invalid LLTV: must be one of 0.385, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965 or 0.98 (scaled by 1e18)";
|
|
715
|
+
}
|
|
726
716
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
717
|
+
).transform((lltv) => from(lltv));
|
|
718
|
+
|
|
719
|
+
// src/core/Collateral.ts
|
|
720
|
+
var CollateralSchema = z6.object({
|
|
721
|
+
asset: z6.string().transform(transformAddress),
|
|
722
|
+
oracle: z6.string().transform(transformAddress),
|
|
723
|
+
lltv: LLTVSchema
|
|
724
|
+
});
|
|
725
|
+
var CollateralsSchema = z6.array(CollateralSchema).min(1, { message: "At least one collateral is required" }).refine(
|
|
726
|
+
(collaterals) => {
|
|
727
|
+
for (let i = 1; i < collaterals.length; i++) {
|
|
728
|
+
if (collaterals[i - 1].asset.toLowerCase() > collaterals[i].asset.toLowerCase()) {
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return true;
|
|
735
733
|
},
|
|
736
734
|
{
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
735
|
+
message: "Collaterals must be sorted alphabetically by address"
|
|
736
|
+
}
|
|
737
|
+
).refine(
|
|
738
|
+
(collaterals) => {
|
|
739
|
+
const uniqueAssets = /* @__PURE__ */ new Set();
|
|
740
|
+
for (const collateral of collaterals) {
|
|
741
|
+
const assetAddress = collateral.asset.toLowerCase();
|
|
742
|
+
if (uniqueAssets.has(assetAddress)) {
|
|
743
|
+
return false;
|
|
744
|
+
}
|
|
745
|
+
uniqueAssets.add(assetAddress);
|
|
746
|
+
}
|
|
747
|
+
return true;
|
|
742
748
|
},
|
|
743
749
|
{
|
|
744
|
-
|
|
745
|
-
name: "maxWithdraw",
|
|
746
|
-
inputs: [{ name: "owner", type: "address" }],
|
|
747
|
-
outputs: [{ name: "", type: "uint256" }],
|
|
748
|
-
stateMutability: "view"
|
|
750
|
+
message: "Collaterals must not contain duplicate assets"
|
|
749
751
|
}
|
|
750
|
-
|
|
751
|
-
var
|
|
752
|
-
{
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
type: "address",
|
|
759
|
-
internalType: "address"
|
|
760
|
-
},
|
|
761
|
-
{
|
|
762
|
-
name: "",
|
|
763
|
-
type: "bytes32",
|
|
764
|
-
internalType: "bytes32"
|
|
765
|
-
},
|
|
766
|
-
{
|
|
767
|
-
name: "",
|
|
768
|
-
type: "address",
|
|
769
|
-
internalType: "address"
|
|
770
|
-
}
|
|
771
|
-
],
|
|
772
|
-
outputs: [
|
|
773
|
-
{
|
|
774
|
-
name: "",
|
|
775
|
-
type: "uint256",
|
|
776
|
-
internalType: "uint256"
|
|
777
|
-
}
|
|
778
|
-
],
|
|
779
|
-
stateMutability: "view"
|
|
780
|
-
},
|
|
781
|
-
{
|
|
782
|
-
type: "function",
|
|
783
|
-
name: "debtOf",
|
|
784
|
-
inputs: [
|
|
785
|
-
{
|
|
786
|
-
name: "",
|
|
787
|
-
type: "address",
|
|
788
|
-
internalType: "address"
|
|
789
|
-
},
|
|
790
|
-
{
|
|
791
|
-
name: "",
|
|
792
|
-
type: "bytes32",
|
|
793
|
-
internalType: "bytes32"
|
|
794
|
-
}
|
|
795
|
-
],
|
|
796
|
-
outputs: [
|
|
797
|
-
{
|
|
798
|
-
name: "",
|
|
799
|
-
type: "uint256",
|
|
800
|
-
internalType: "uint256"
|
|
801
|
-
}
|
|
802
|
-
],
|
|
803
|
-
stateMutability: "view"
|
|
804
|
-
},
|
|
805
|
-
{
|
|
806
|
-
type: "function",
|
|
807
|
-
name: "market",
|
|
808
|
-
inputs: [
|
|
809
|
-
{
|
|
810
|
-
name: "id",
|
|
811
|
-
type: "bytes32",
|
|
812
|
-
internalType: "Id"
|
|
813
|
-
}
|
|
814
|
-
],
|
|
815
|
-
outputs: [
|
|
816
|
-
{
|
|
817
|
-
name: "totalSupplyAssets",
|
|
818
|
-
type: "uint128",
|
|
819
|
-
internalType: "uint128"
|
|
820
|
-
},
|
|
821
|
-
{
|
|
822
|
-
name: "totalSupplyShares",
|
|
823
|
-
type: "uint128",
|
|
824
|
-
internalType: "uint128"
|
|
825
|
-
},
|
|
826
|
-
{
|
|
827
|
-
name: "totalBorrowAssets",
|
|
828
|
-
type: "uint128",
|
|
829
|
-
internalType: "uint128"
|
|
830
|
-
},
|
|
831
|
-
{
|
|
832
|
-
name: "totalBorrowShares",
|
|
833
|
-
type: "uint128",
|
|
834
|
-
internalType: "uint128"
|
|
835
|
-
},
|
|
836
|
-
{
|
|
837
|
-
name: "lastUpdate",
|
|
838
|
-
type: "uint128",
|
|
839
|
-
internalType: "uint128"
|
|
840
|
-
},
|
|
841
|
-
{
|
|
842
|
-
name: "fee",
|
|
843
|
-
type: "uint128",
|
|
844
|
-
internalType: "uint128"
|
|
845
|
-
}
|
|
846
|
-
],
|
|
847
|
-
stateMutability: "view"
|
|
848
|
-
},
|
|
849
|
-
{
|
|
850
|
-
type: "function",
|
|
851
|
-
name: "position",
|
|
852
|
-
inputs: [
|
|
853
|
-
{
|
|
854
|
-
name: "id",
|
|
855
|
-
type: "bytes32",
|
|
856
|
-
internalType: "Id"
|
|
857
|
-
},
|
|
858
|
-
{
|
|
859
|
-
name: "user",
|
|
860
|
-
type: "address",
|
|
861
|
-
internalType: "address"
|
|
862
|
-
}
|
|
863
|
-
],
|
|
864
|
-
outputs: [
|
|
865
|
-
{
|
|
866
|
-
name: "supplyShares",
|
|
867
|
-
type: "uint256",
|
|
868
|
-
internalType: "uint256"
|
|
869
|
-
},
|
|
870
|
-
{
|
|
871
|
-
name: "borrowShares",
|
|
872
|
-
type: "uint128",
|
|
873
|
-
internalType: "uint128"
|
|
874
|
-
},
|
|
875
|
-
{
|
|
876
|
-
name: "collateral",
|
|
877
|
-
type: "uint128",
|
|
878
|
-
internalType: "uint128"
|
|
879
|
-
}
|
|
880
|
-
],
|
|
881
|
-
stateMutability: "view"
|
|
882
|
-
}
|
|
883
|
-
];
|
|
752
|
+
);
|
|
753
|
+
var from2 = (parameters) => {
|
|
754
|
+
return {
|
|
755
|
+
asset: parameters.asset.toLowerCase(),
|
|
756
|
+
lltv: from(parameters.lltv),
|
|
757
|
+
oracle: parameters.oracle.toLowerCase()
|
|
758
|
+
};
|
|
759
|
+
};
|
|
884
760
|
|
|
885
|
-
// src/core/
|
|
886
|
-
var
|
|
887
|
-
__export(
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
761
|
+
// src/core/Liquidity.ts
|
|
762
|
+
var Liquidity_exports = {};
|
|
763
|
+
__export(Liquidity_exports, {
|
|
764
|
+
calculateMaxDebt: () => calculateMaxDebt,
|
|
765
|
+
generateAllowancePoolId: () => generateAllowancePoolId,
|
|
766
|
+
generateBalancePoolId: () => generateBalancePoolId,
|
|
767
|
+
generateBuyVaultCallbackPoolId: () => generateBuyVaultCallbackPoolId,
|
|
768
|
+
generateDebtPoolId: () => generateDebtPoolId,
|
|
769
|
+
generateMarketLiquidityPoolId: () => generateMarketLiquidityPoolId,
|
|
770
|
+
generateObligationCollateralPoolId: () => generateObligationCollateralPoolId,
|
|
771
|
+
generateSellERC20CallbackPoolId: () => generateSellERC20CallbackPoolId,
|
|
772
|
+
generateUserVaultPositionPoolId: () => generateUserVaultPositionPoolId,
|
|
773
|
+
generateVaultPositionPoolId: () => generateVaultPositionPoolId
|
|
894
774
|
});
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
var WhitelistedCallbackAddresses = {
|
|
902
|
-
["buy_with_empty_callback" /* BuyWithEmptyCallback */]: [],
|
|
903
|
-
["buy_vault_v1_callback" /* BuyVaultV1Callback */]: [
|
|
904
|
-
"0x3333333333333333333333333333333333333333",
|
|
905
|
-
"0x4444444444444444444444444444444444444444"
|
|
906
|
-
// @TODO: update once deployed and add mapping per chain if needed
|
|
907
|
-
].map((address) => address.toLowerCase()),
|
|
908
|
-
["sell_erc20_callback" /* SellERC20Callback */]: [
|
|
909
|
-
"0x1111111111111111111111111111111111111111",
|
|
910
|
-
"0x2222222222222222222222222222222222222222"
|
|
911
|
-
// @TODO: update once deployed and add mapping per chain if needed
|
|
912
|
-
].map((address) => address.toLowerCase())
|
|
913
|
-
};
|
|
914
|
-
function decodeBuyVaultV1Callback(data) {
|
|
915
|
-
if (!data || data === "0x") throw new Error("Empty callback data");
|
|
916
|
-
try {
|
|
917
|
-
const [vaults, amounts] = decodeAbiParameters(
|
|
918
|
-
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
919
|
-
data
|
|
920
|
-
);
|
|
921
|
-
if (vaults.length !== amounts.length) {
|
|
922
|
-
throw new Error("Mismatched array lengths");
|
|
923
|
-
}
|
|
924
|
-
return vaults.map((v, i) => ({ vault: v, amount: amounts[i] }));
|
|
925
|
-
} catch (_) {
|
|
926
|
-
throw new Error("Invalid BuyVaultV1Callback callback data");
|
|
927
|
-
}
|
|
775
|
+
function calculateMaxDebt(amount, oraclePrice, lltv) {
|
|
776
|
+
const ORACLE_PRICE_SCALE = 10n ** 36n;
|
|
777
|
+
const PRECISION = 10n ** 18n;
|
|
778
|
+
const collateralQuoted = amount * oraclePrice / ORACLE_PRICE_SCALE;
|
|
779
|
+
const maxDebt = collateralQuoted * lltv / PRECISION;
|
|
780
|
+
return maxDebt;
|
|
928
781
|
}
|
|
929
|
-
function
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
const [collaterals, amounts] = decodeAbiParameters(
|
|
933
|
-
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
934
|
-
data
|
|
935
|
-
);
|
|
936
|
-
if (collaterals.length !== amounts.length) {
|
|
937
|
-
throw new Error("Mismatched array lengths");
|
|
938
|
-
}
|
|
939
|
-
return collaterals.map((c, i) => ({ collateral: c, amount: amounts[i] }));
|
|
940
|
-
} catch (_) {
|
|
941
|
-
throw new Error("Invalid SellERC20Callback callback data");
|
|
942
|
-
}
|
|
782
|
+
function generateBalancePoolId(parameters) {
|
|
783
|
+
const { user, chainId, token } = parameters;
|
|
784
|
+
return `${user}-${chainId.toString()}-${token}-balance`.toLowerCase();
|
|
943
785
|
}
|
|
944
|
-
function
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
[parameters.vaults, parameters.amounts]
|
|
948
|
-
);
|
|
786
|
+
function generateAllowancePoolId(parameters) {
|
|
787
|
+
const { user, chainId, token } = parameters;
|
|
788
|
+
return `${user}-${chainId.toString()}-${token}-allowance`.toLowerCase();
|
|
949
789
|
}
|
|
950
|
-
function
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
790
|
+
function generateSellERC20CallbackPoolId(parameters) {
|
|
791
|
+
const { user, chainId, obligationId: obligationId2, token, offerHash } = parameters;
|
|
792
|
+
return `${user}-${chainId.toString()}-${obligationId2}-${token}-${offerHash}-sell_erc20_callback`.toLowerCase();
|
|
793
|
+
}
|
|
794
|
+
function generateObligationCollateralPoolId(parameters) {
|
|
795
|
+
const { user, chainId, obligationId: obligationId2, token } = parameters;
|
|
796
|
+
return `${user}-${chainId.toString()}-${obligationId2}-${token}-obligation-collateral`.toLowerCase();
|
|
797
|
+
}
|
|
798
|
+
function generateBuyVaultCallbackPoolId(parameters) {
|
|
799
|
+
const { user, chainId, vault, offerHash } = parameters;
|
|
800
|
+
return `${user}-${chainId.toString()}-${vault}-${offerHash}-${"buy_vault_v1_callback" /* BuyVaultV1Callback */}`.toLowerCase();
|
|
801
|
+
}
|
|
802
|
+
function generateDebtPoolId(parameters) {
|
|
803
|
+
const { user, chainId, obligationId: obligationId2 } = parameters;
|
|
804
|
+
return `${user}-${chainId.toString()}-${obligationId2}-debt`.toLowerCase();
|
|
805
|
+
}
|
|
806
|
+
function generateUserVaultPositionPoolId(parameters) {
|
|
807
|
+
const { user, chainId, vault } = parameters;
|
|
808
|
+
return `${user}-${chainId.toString()}-${vault}-user-vault-position`.toLowerCase();
|
|
809
|
+
}
|
|
810
|
+
function generateVaultPositionPoolId(parameters) {
|
|
811
|
+
const { vault, chainId, marketId } = parameters;
|
|
812
|
+
return `${vault}-${chainId.toString()}-${marketId}-vault-position`.toLowerCase();
|
|
813
|
+
}
|
|
814
|
+
function generateMarketLiquidityPoolId(parameters) {
|
|
815
|
+
const { chainId, marketId } = parameters;
|
|
816
|
+
return `${chainId.toString()}-${marketId}-market-liquidity`.toLowerCase();
|
|
955
817
|
}
|
|
956
818
|
|
|
957
|
-
// src/core/
|
|
958
|
-
var
|
|
959
|
-
__export(
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
chainIds: () => chainIds,
|
|
966
|
-
chainNames: () => chainNames,
|
|
967
|
-
chains: () => chains,
|
|
968
|
-
getChain: () => getChain,
|
|
969
|
-
getWhitelistedChains: () => getWhitelistedChains,
|
|
970
|
-
streamLogs: () => streamLogs
|
|
819
|
+
// src/core/Maturity.ts
|
|
820
|
+
var Maturity_exports = {};
|
|
821
|
+
__export(Maturity_exports, {
|
|
822
|
+
InvalidDateError: () => InvalidDateError,
|
|
823
|
+
InvalidFormatError: () => InvalidFormatError,
|
|
824
|
+
InvalidOptionError: () => InvalidOptionError2,
|
|
825
|
+
MaturitySchema: () => MaturitySchema,
|
|
826
|
+
from: () => from3
|
|
971
827
|
});
|
|
972
|
-
var
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
};
|
|
980
|
-
var chainIds = new Set(Object.values(ChainId));
|
|
981
|
-
var chainNameLookup = new Map(Object.entries(ChainId).map(([key, value]) => [value, key]));
|
|
982
|
-
function getChain(chainId) {
|
|
983
|
-
const chainName = chainNameLookup.get(chainId)?.toLowerCase();
|
|
984
|
-
if (!chainName) {
|
|
985
|
-
return void 0;
|
|
986
|
-
}
|
|
987
|
-
return chains[chainName];
|
|
988
|
-
}
|
|
989
|
-
var getWhitelistedChains = () => {
|
|
990
|
-
return [chains.ethereum, chains.base, chains["ethereum-virtual-testnet"], chains.anvil];
|
|
991
|
-
};
|
|
992
|
-
var chains = {
|
|
993
|
-
ethereum: {
|
|
994
|
-
...mainnet,
|
|
995
|
-
id: ChainId.ETHEREUM,
|
|
996
|
-
name: "ethereum",
|
|
997
|
-
whitelistedAssets: new Set(
|
|
998
|
-
[
|
|
999
|
-
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
1000
|
-
// USDC
|
|
1001
|
-
"0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
|
1002
|
-
// DAI
|
|
1003
|
-
].map((address) => address.toLowerCase())
|
|
1004
|
-
),
|
|
1005
|
-
morpho: "0x0000000000000000000000000000000000000000",
|
|
1006
|
-
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
1007
|
-
mempool: {
|
|
1008
|
-
address: "0x0000000000000000000000000000000000000000",
|
|
1009
|
-
deploymentBlock: 23347674,
|
|
1010
|
-
reindexBuffer: 10
|
|
1011
|
-
},
|
|
1012
|
-
vaultV1Factory: {
|
|
1013
|
-
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
1014
|
-
"v1.1": "0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
1015
|
-
}
|
|
1016
|
-
},
|
|
1017
|
-
base: {
|
|
1018
|
-
...base,
|
|
1019
|
-
id: ChainId.BASE,
|
|
1020
|
-
name: "base",
|
|
1021
|
-
whitelistedAssets: new Set(
|
|
1022
|
-
[
|
|
1023
|
-
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
1024
|
-
// USDC
|
|
1025
|
-
"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb"
|
|
1026
|
-
// DAI
|
|
1027
|
-
].map((address) => address.toLowerCase())
|
|
1028
|
-
),
|
|
1029
|
-
morpho: "0x0000000000000000000000000000000000000000",
|
|
1030
|
-
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
1031
|
-
mempool: {
|
|
1032
|
-
address: "0x0000000000000000000000000000000000000000",
|
|
1033
|
-
deploymentBlock: 35449942,
|
|
1034
|
-
reindexBuffer: 10
|
|
1035
|
-
},
|
|
1036
|
-
vaultV1Factory: {
|
|
1037
|
-
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
1038
|
-
"v1.1": "0xFf62A7c278C62eD665133147129245053Bbf5918"
|
|
1039
|
-
}
|
|
1040
|
-
},
|
|
1041
|
-
"ethereum-virtual-testnet": {
|
|
1042
|
-
...mainnet,
|
|
1043
|
-
id: ChainId["ETHEREUM-VIRTUAL-TESTNET"],
|
|
1044
|
-
name: "ethereum-virtual-testnet",
|
|
1045
|
-
whitelistedAssets: new Set(
|
|
1046
|
-
[
|
|
1047
|
-
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
1048
|
-
// USDC
|
|
1049
|
-
"0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
|
1050
|
-
// DAI
|
|
1051
|
-
].map((address) => address.toLowerCase())
|
|
1052
|
-
),
|
|
1053
|
-
morpho: "0x11a002d45db720ed47a80d2f3489cba5b833eaf5",
|
|
1054
|
-
// @TODO: This is mock Consumed contract, update with Terms once stable
|
|
1055
|
-
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
1056
|
-
mempool: {
|
|
1057
|
-
address: "0x5b06224f736a57635b5bcb50b8ef178b189107cb",
|
|
1058
|
-
deploymentBlock: 23224302,
|
|
1059
|
-
reindexBuffer: 10
|
|
1060
|
-
},
|
|
1061
|
-
vaultV1Factory: {
|
|
1062
|
-
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
1063
|
-
"v1.1": "0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
828
|
+
var MaturitySchema = z6.number().int().refine(
|
|
829
|
+
(maturity) => {
|
|
830
|
+
try {
|
|
831
|
+
from3(maturity);
|
|
832
|
+
return true;
|
|
833
|
+
} catch (_e) {
|
|
834
|
+
return false;
|
|
1064
835
|
}
|
|
1065
836
|
},
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
"0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
|
1075
|
-
// DAI
|
|
1076
|
-
].map((address) => address.toLowerCase())
|
|
1077
|
-
),
|
|
1078
|
-
morpho: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
|
|
1079
|
-
morphoBlue: "0x0000000000000000000000000000000000000000",
|
|
1080
|
-
// Set dynamically in tests
|
|
1081
|
-
mempool: {
|
|
1082
|
-
address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
|
|
1083
|
-
deploymentBlock: 23223727,
|
|
1084
|
-
reindexBuffer: 10
|
|
1085
|
-
},
|
|
1086
|
-
vaultV1Factory: {
|
|
1087
|
-
"v1.0": "0x0000000000000000000000000000000000000000",
|
|
1088
|
-
"v1.1": "0x0000000000000000000000000000000000000000"
|
|
837
|
+
{
|
|
838
|
+
error: (issue) => {
|
|
839
|
+
try {
|
|
840
|
+
const maturityDate = new Date(issue.input * 1e3);
|
|
841
|
+
return `The maturity is set to ${maturityDate}. It must fall on the allowed settlement cycles (Friday 15:00 UTC at the end of week/month/quarter).`;
|
|
842
|
+
} catch (_) {
|
|
843
|
+
return `The maturity is set to ${issue.input}. It must fall on the allowed settlement cycles (Friday 15:00 UTC at the end of week/month/quarter).`;
|
|
844
|
+
}
|
|
1089
845
|
}
|
|
1090
846
|
}
|
|
847
|
+
).transform((maturity) => maturity);
|
|
848
|
+
var MaturityOptions = {
|
|
849
|
+
end_of_week: () => endOfWeek(),
|
|
850
|
+
end_of_next_week: () => endOfNextWeek(),
|
|
851
|
+
end_of_month: () => endOfMonth(),
|
|
852
|
+
end_of_next_month: () => endOfNextMonth(),
|
|
853
|
+
end_of_quarter: () => endOfQuarter(),
|
|
854
|
+
end_of_next_quarter: () => endOfNextQuarter()
|
|
1091
855
|
};
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
async function* streamLogs(parameters) {
|
|
1097
|
-
const {
|
|
1098
|
-
client,
|
|
1099
|
-
contractAddress,
|
|
1100
|
-
event,
|
|
1101
|
-
blockNumberGte,
|
|
1102
|
-
blockNumberLte,
|
|
1103
|
-
order = "desc",
|
|
1104
|
-
options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = DEFAULT_BLOCK_WINDOW } = {}
|
|
1105
|
-
} = parameters;
|
|
1106
|
-
if (maxBatchSize > MAX_BATCH_SIZE) throw new InvalidBatchSizeError(maxBatchSize);
|
|
1107
|
-
if (blockWindow > MAX_BLOCK_WINDOW) throw new InvalidBlockWindowError(blockWindow);
|
|
1108
|
-
if (order === "asc" && blockNumberGte === void 0) throw new MissingBlockNumberError();
|
|
1109
|
-
const latestBlock = (await getBlock(client, { blockTag: "latest", includeTransactions: false })).number;
|
|
1110
|
-
let toBlock = 0n;
|
|
1111
|
-
if (order === "asc")
|
|
1112
|
-
toBlock = min(BigInt(blockNumberGte) + BigInt(blockWindow), latestBlock);
|
|
1113
|
-
if (order === "desc")
|
|
1114
|
-
toBlock = blockNumberLte === void 0 ? latestBlock : min(BigInt(blockNumberLte), latestBlock);
|
|
1115
|
-
let fromBlock = 0n;
|
|
1116
|
-
if (order === "asc") fromBlock = min(BigInt(blockNumberGte), latestBlock);
|
|
1117
|
-
if (order === "desc")
|
|
1118
|
-
fromBlock = max(BigInt(blockNumberGte || toBlock - BigInt(blockWindow)), 0n);
|
|
1119
|
-
if (order === "asc") toBlock = min(toBlock, fromBlock + BigInt(blockWindow));
|
|
1120
|
-
if (order === "desc") fromBlock = max(fromBlock, toBlock - BigInt(blockWindow));
|
|
1121
|
-
if (fromBlock > toBlock) throw new InvalidBlockRangeError(fromBlock, toBlock);
|
|
1122
|
-
let streaming = true;
|
|
1123
|
-
while (streaming) {
|
|
1124
|
-
const logs = await getLogs(client, {
|
|
1125
|
-
address: contractAddress,
|
|
1126
|
-
event,
|
|
1127
|
-
fromBlock,
|
|
1128
|
-
toBlock
|
|
1129
|
-
});
|
|
1130
|
-
logs.sort((a, b) => {
|
|
1131
|
-
if (a.blockNumber !== b.blockNumber)
|
|
1132
|
-
return order === "asc" ? Number(a.blockNumber - b.blockNumber) : Number(b.blockNumber - a.blockNumber);
|
|
1133
|
-
if (a.transactionIndex !== b.transactionIndex)
|
|
1134
|
-
return order === "asc" ? a.transactionIndex - b.transactionIndex : b.transactionIndex - a.transactionIndex;
|
|
1135
|
-
return order === "asc" ? a.logIndex - b.logIndex : b.logIndex - a.logIndex;
|
|
1136
|
-
});
|
|
1137
|
-
for (const logBatch of batch(logs, maxBatchSize)) {
|
|
1138
|
-
if (logBatch.length === 0) break;
|
|
1139
|
-
yield {
|
|
1140
|
-
logs: logBatch,
|
|
1141
|
-
blockNumber: logBatch.length === maxBatchSize ? (
|
|
1142
|
-
// if the batch is full, return the last block number, block numbers are always sorted
|
|
1143
|
-
Number(logBatch[logBatch.length - 1]?.blockNumber)
|
|
1144
|
-
) : (
|
|
1145
|
-
// if the batch is not full, return `toBlock` or `fromBlock` to indicate until which block the logs were fetched
|
|
1146
|
-
order === "asc" ? Number(toBlock) : Number(fromBlock)
|
|
1147
|
-
)
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
1150
|
-
streaming = order === "asc" ? toBlock < (blockNumberLte || latestBlock) : fromBlock > (blockNumberGte || 0n);
|
|
1151
|
-
if (order === "asc") {
|
|
1152
|
-
fromBlock = min(BigInt(toBlock) + 1n, latestBlock);
|
|
1153
|
-
toBlock = min(fromBlock + BigInt(blockWindow), latestBlock);
|
|
1154
|
-
}
|
|
1155
|
-
if (order === "desc") {
|
|
1156
|
-
const lowerBound = BigInt(blockNumberGte || 0);
|
|
1157
|
-
const windowSize = BigInt(blockWindow);
|
|
1158
|
-
const nextToBlock = max(fromBlock - 1n, lowerBound);
|
|
1159
|
-
const nextFromBlock = max(nextToBlock - windowSize, lowerBound);
|
|
1160
|
-
toBlock = nextToBlock;
|
|
1161
|
-
fromBlock = nextFromBlock;
|
|
1162
|
-
}
|
|
856
|
+
function from3(ts) {
|
|
857
|
+
if (typeof ts === "string") {
|
|
858
|
+
if (ts in MaturityOptions) return MaturityOptions[ts]();
|
|
859
|
+
throw new InvalidOptionError2(ts);
|
|
1163
860
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
861
|
+
if (typeof ts === "number" && ts > 1e12) throw new InvalidFormatError();
|
|
862
|
+
if (!Object.values(MaturityOptions).some((option) => option() === ts))
|
|
863
|
+
throw new InvalidDateError(ts);
|
|
864
|
+
return ts;
|
|
1166
865
|
}
|
|
1167
|
-
var
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
866
|
+
var endOfWeek = () => fridayOfWeek(0);
|
|
867
|
+
var endOfNextWeek = () => fridayOfWeek(1);
|
|
868
|
+
var endOfMonth = () => lastFridayOfMonth((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth());
|
|
869
|
+
var endOfNextMonth = () => lastFridayOfMonth((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth() + 1);
|
|
870
|
+
var endOfQuarter = () => lastFridayOfQuarter(0);
|
|
871
|
+
var endOfNextQuarter = () => lastFridayOfQuarter(1);
|
|
872
|
+
var fridayOfWeek = (weeksAhead = 0) => {
|
|
873
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
874
|
+
const today15H = new Date(
|
|
875
|
+
Date.UTC(now2.getUTCFullYear(), now2.getUTCMonth(), now2.getUTCDate(), 15)
|
|
876
|
+
);
|
|
877
|
+
let daysUntilFriday = (5 - today15H.getUTCDay() + 7) % 7;
|
|
878
|
+
if (daysUntilFriday === 0 && now2.getTime() >= today15H.getTime()) {
|
|
879
|
+
daysUntilFriday = 7;
|
|
1173
880
|
}
|
|
881
|
+
const friday = new Date(today15H);
|
|
882
|
+
friday.setUTCDate(friday.getUTCDate() + daysUntilFriday + weeksAhead * 7);
|
|
883
|
+
return friday.getTime() / 1e3;
|
|
1174
884
|
};
|
|
1175
|
-
var
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
`Invalid block window while streaming data from chain. Maximum is ${MAX_BLOCK_WINDOW}. Got ${blockWindow}.`
|
|
1180
|
-
);
|
|
885
|
+
var lastFridayOfMonth = (year, month) => {
|
|
886
|
+
const lastDayOfMonth15H = new Date(Date.UTC(year, month + 1, 0, 15));
|
|
887
|
+
while (lastDayOfMonth15H.getUTCDay() !== 5) {
|
|
888
|
+
lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate() - 1);
|
|
1181
889
|
}
|
|
890
|
+
const maturity = lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate()) / 1e3;
|
|
891
|
+
return maturity;
|
|
1182
892
|
};
|
|
1183
|
-
var
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
893
|
+
var lastFridayOfQuarter = (quartersAhead = 0) => {
|
|
894
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
895
|
+
const quarterIndex = Math.floor(now2.getUTCMonth() / 3) + quartersAhead;
|
|
896
|
+
const year = now2.getUTCFullYear() + Math.floor(quarterIndex / 4);
|
|
897
|
+
const quarter = quarterIndex % 4;
|
|
898
|
+
const lastMonth = quarter * 3 + 2;
|
|
899
|
+
return lastFridayOfMonth(year, lastMonth);
|
|
1190
900
|
};
|
|
1191
|
-
var
|
|
1192
|
-
name = "
|
|
901
|
+
var InvalidFormatError = class extends BaseError {
|
|
902
|
+
name = "Maturity.InvalidFormatError";
|
|
1193
903
|
constructor() {
|
|
1194
|
-
super("
|
|
904
|
+
super("Invalid maturity format. Maturity should be expressed in seconds.");
|
|
1195
905
|
}
|
|
1196
906
|
};
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
var Collateral_exports = {};
|
|
1200
|
-
__export(Collateral_exports, {
|
|
1201
|
-
CollateralSchema: () => CollateralSchema,
|
|
1202
|
-
CollateralsSchema: () => CollateralsSchema,
|
|
1203
|
-
from: () => from2
|
|
1204
|
-
});
|
|
1205
|
-
var transformHex = (val, ctx) => {
|
|
1206
|
-
if (isHex(val)) return val;
|
|
1207
|
-
ctx.addIssue({
|
|
1208
|
-
code: "invalid_format",
|
|
1209
|
-
input: val,
|
|
1210
|
-
format: "hex",
|
|
1211
|
-
error: "not a hex"
|
|
1212
|
-
});
|
|
1213
|
-
return z6.NEVER;
|
|
1214
|
-
};
|
|
1215
|
-
var transformAddress = (val, ctx) => {
|
|
1216
|
-
if (isAddress(val.toLowerCase())) return val.toLowerCase();
|
|
1217
|
-
ctx.addIssue({
|
|
1218
|
-
code: "invalid_format",
|
|
1219
|
-
input: val,
|
|
1220
|
-
format: "address",
|
|
1221
|
-
error: "not a valid address"
|
|
1222
|
-
});
|
|
1223
|
-
return z6.NEVER;
|
|
1224
|
-
};
|
|
1225
|
-
|
|
1226
|
-
// src/core/LLTV.ts
|
|
1227
|
-
var LLTV_exports = {};
|
|
1228
|
-
__export(LLTV_exports, {
|
|
1229
|
-
InvalidLLTVError: () => InvalidLLTVError,
|
|
1230
|
-
InvalidOptionError: () => InvalidOptionError,
|
|
1231
|
-
LLTVSchema: () => LLTVSchema,
|
|
1232
|
-
Options: () => Options,
|
|
1233
|
-
from: () => from
|
|
1234
|
-
});
|
|
1235
|
-
var Options = [0.385, 0.5, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965, 0.98];
|
|
1236
|
-
var LLTV_SCALED = Options.map((lltv) => BigInt(lltv * 10 ** 18));
|
|
1237
|
-
function from(lltv) {
|
|
1238
|
-
if (typeof lltv === "bigint" && !LLTV_SCALED.includes(lltv)) throw new InvalidLLTVError(lltv);
|
|
1239
|
-
if (typeof lltv === "bigint") return lltv;
|
|
1240
|
-
if (typeof lltv === "number" && !Options.includes(lltv)) throw new InvalidOptionError(lltv);
|
|
1241
|
-
return BigInt(lltv * 10 ** 18);
|
|
1242
|
-
}
|
|
1243
|
-
var InvalidOptionError = class extends BaseError {
|
|
1244
|
-
name = "LLTV.InvalidOptionError";
|
|
907
|
+
var InvalidDateError = class extends BaseError {
|
|
908
|
+
name = "Maturity.InvalidDateError";
|
|
1245
909
|
constructor(input) {
|
|
1246
910
|
super(
|
|
1247
|
-
`Invalid
|
|
1248
|
-
|
|
1249
|
-
).join(", ")}.`
|
|
911
|
+
`Invalid maturity date. Input: "${input}". Accepted values are: ${Object.values(
|
|
912
|
+
MaturityOptions
|
|
913
|
+
).map((option) => `"${option()}"`).join(", ")}.`
|
|
1250
914
|
);
|
|
1251
915
|
}
|
|
1252
916
|
};
|
|
1253
|
-
var
|
|
1254
|
-
name = "
|
|
917
|
+
var InvalidOptionError2 = class extends BaseError {
|
|
918
|
+
name = "Maturity.InvalidOptionError";
|
|
1255
919
|
constructor(input) {
|
|
1256
920
|
super(
|
|
1257
|
-
`Invalid
|
|
1258
|
-
|
|
1259
|
-
).join(", ")}.`
|
|
921
|
+
`Invalid maturity option. Input: "${input}". Accepted values are: ${Object.keys(
|
|
922
|
+
MaturityOptions
|
|
923
|
+
).map((option) => `"${option}"`).join(", ")}.`
|
|
1260
924
|
);
|
|
1261
925
|
}
|
|
1262
926
|
};
|
|
1263
|
-
var LLTVSchema = z6.bigint({ coerce: true }).refine(
|
|
1264
|
-
(lltv) => {
|
|
1265
|
-
try {
|
|
1266
|
-
from(lltv);
|
|
1267
|
-
return true;
|
|
1268
|
-
} catch (_) {
|
|
1269
|
-
return false;
|
|
1270
|
-
}
|
|
1271
|
-
},
|
|
1272
|
-
{
|
|
1273
|
-
error: () => {
|
|
1274
|
-
return "Invalid LLTV: must be one of 0.385, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965 or 0.98 (scaled by 1e18)";
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
).transform((lltv) => from(lltv));
|
|
1278
927
|
|
|
1279
|
-
// src/core/
|
|
1280
|
-
var
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
928
|
+
// src/core/Obligation.ts
|
|
929
|
+
var Obligation_exports = {};
|
|
930
|
+
__export(Obligation_exports, {
|
|
931
|
+
CollateralsAreNotSortedError: () => CollateralsAreNotSortedError,
|
|
932
|
+
InvalidObligationError: () => InvalidObligationError,
|
|
933
|
+
ObligationSchema: () => ObligationSchema,
|
|
934
|
+
from: () => from4,
|
|
935
|
+
fromSnakeCase: () => fromSnakeCase2,
|
|
936
|
+
id: () => id,
|
|
937
|
+
random: () => random
|
|
1284
938
|
});
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
).
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
939
|
+
|
|
940
|
+
// src/utils/Format.ts
|
|
941
|
+
var Format_exports = {};
|
|
942
|
+
__export(Format_exports, {
|
|
943
|
+
fromSnakeCase: () => fromSnakeCase,
|
|
944
|
+
toSnakeCase: () => toSnakeCase
|
|
945
|
+
});
|
|
946
|
+
function toSnakeCase(obj) {
|
|
947
|
+
return stringifyBigint(
|
|
948
|
+
processObject(
|
|
949
|
+
obj,
|
|
950
|
+
(s2) => s2.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`),
|
|
951
|
+
(value) => typeof value === "string" && isAddress(value.toLowerCase()) ? getAddress(value.toLowerCase()) : value
|
|
952
|
+
)
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
function fromSnakeCase(obj) {
|
|
956
|
+
return processObject(
|
|
957
|
+
obj,
|
|
958
|
+
(s2) => isAddress(s2.toLowerCase()) ? s2 : s2.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),
|
|
959
|
+
(value) => typeof value === "string" && isAddress(value.toLowerCase()) ? value.toLowerCase() : value
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
function processObject(obj, fnKey, fnValue) {
|
|
963
|
+
if (typeof obj !== "object" || obj === null) return obj;
|
|
964
|
+
if (Array.isArray(obj)) return obj.map((item) => processObject(item, fnKey, fnValue));
|
|
965
|
+
return Object.entries(obj).reduce(
|
|
966
|
+
(acc, [key, value]) => {
|
|
967
|
+
const newKey = fnKey(key);
|
|
968
|
+
acc[newKey] = typeof value === "object" && value !== null ? processObject(value, fnKey, fnValue) : fnValue(value);
|
|
969
|
+
return acc;
|
|
970
|
+
},
|
|
971
|
+
{}
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
function stringifyBigint(value) {
|
|
975
|
+
if (typeof value === "bigint") return value.toString();
|
|
976
|
+
if (Array.isArray(value)) return value.map(stringifyBigint);
|
|
977
|
+
if (value && typeof value === "object") {
|
|
978
|
+
const out = {};
|
|
979
|
+
for (const [k, v] of Object.entries(value)) {
|
|
980
|
+
out[k] = stringifyBigint(v);
|
|
1306
981
|
}
|
|
1307
|
-
return
|
|
1308
|
-
},
|
|
1309
|
-
{
|
|
1310
|
-
message: "Collaterals must not contain duplicate assets"
|
|
982
|
+
return out;
|
|
1311
983
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
return {
|
|
1315
|
-
asset: parameters.asset.toLowerCase(),
|
|
1316
|
-
lltv: from(parameters.lltv),
|
|
1317
|
-
oracle: parameters.oracle.toLowerCase()
|
|
1318
|
-
};
|
|
1319
|
-
};
|
|
984
|
+
return value;
|
|
985
|
+
}
|
|
1320
986
|
|
|
1321
|
-
// src/core/
|
|
1322
|
-
var
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
987
|
+
// src/core/Obligation.ts
|
|
988
|
+
var ObligationSchema = z6.object({
|
|
989
|
+
chainId: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
990
|
+
loanToken: z6.string().transform(transformAddress),
|
|
991
|
+
collaterals: CollateralsSchema,
|
|
992
|
+
maturity: MaturitySchema
|
|
1327
993
|
});
|
|
1328
|
-
function
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
994
|
+
function from4(parameters) {
|
|
995
|
+
try {
|
|
996
|
+
const parsedObligation = ObligationSchema.parse({
|
|
997
|
+
...parameters,
|
|
998
|
+
maturity: from3(parameters.maturity)
|
|
999
|
+
});
|
|
1000
|
+
return {
|
|
1001
|
+
chainId: parsedObligation.chainId,
|
|
1002
|
+
loanToken: parsedObligation.loanToken.toLowerCase(),
|
|
1003
|
+
collaterals: parsedObligation.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)),
|
|
1004
|
+
maturity: parsedObligation.maturity
|
|
1005
|
+
};
|
|
1006
|
+
} catch (error2) {
|
|
1007
|
+
throw new InvalidObligationError(error2);
|
|
1337
1008
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1009
|
+
}
|
|
1010
|
+
function fromSnakeCase2(input) {
|
|
1011
|
+
return from4(fromSnakeCase(input));
|
|
1012
|
+
}
|
|
1013
|
+
function id(obligation) {
|
|
1014
|
+
let lastAsset = "";
|
|
1015
|
+
for (const collateral of obligation.collaterals) {
|
|
1016
|
+
const newAsset = collateral.asset.toLowerCase();
|
|
1017
|
+
if (newAsset.localeCompare(lastAsset) < 0) throw new CollateralsAreNotSortedError();
|
|
1018
|
+
lastAsset = newAsset;
|
|
1340
1019
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1020
|
+
return keccak256(
|
|
1021
|
+
encodeAbiParameters(
|
|
1022
|
+
[
|
|
1023
|
+
{ type: "uint256" },
|
|
1024
|
+
{ type: "address" },
|
|
1025
|
+
{
|
|
1026
|
+
type: "tuple[]",
|
|
1027
|
+
components: [
|
|
1028
|
+
{ type: "address", name: "token" },
|
|
1029
|
+
{ type: "uint256", name: "lltv" },
|
|
1030
|
+
{ type: "address", name: "oracle" }
|
|
1031
|
+
]
|
|
1032
|
+
},
|
|
1033
|
+
{ type: "uint256" }
|
|
1034
|
+
],
|
|
1035
|
+
[
|
|
1036
|
+
obligation.chainId,
|
|
1037
|
+
obligation.loanToken.toLowerCase(),
|
|
1038
|
+
obligation.collaterals.map((c) => ({
|
|
1039
|
+
token: c.asset.toLowerCase(),
|
|
1040
|
+
lltv: c.lltv,
|
|
1041
|
+
oracle: c.oracle.toLowerCase()
|
|
1042
|
+
})),
|
|
1043
|
+
BigInt(obligation.maturity)
|
|
1044
|
+
]
|
|
1045
|
+
)
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
function random() {
|
|
1049
|
+
return from4({
|
|
1050
|
+
chainId: 1n,
|
|
1051
|
+
loanToken: privateKeyToAccount(generatePrivateKey()).address,
|
|
1052
|
+
collaterals: [
|
|
1053
|
+
from2({
|
|
1054
|
+
asset: privateKeyToAccount(generatePrivateKey()).address,
|
|
1055
|
+
oracle: privateKeyToAccount(generatePrivateKey()).address,
|
|
1056
|
+
lltv: 0.965
|
|
1057
|
+
})
|
|
1058
|
+
],
|
|
1059
|
+
maturity: from3("end_of_next_quarter")
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
var InvalidObligationError = class extends BaseError {
|
|
1063
|
+
name = "Obligation.InvalidObligationError";
|
|
1064
|
+
constructor(error2) {
|
|
1065
|
+
super("Invalid obligation.", { cause: error2 });
|
|
1379
1066
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1067
|
+
};
|
|
1068
|
+
var CollateralsAreNotSortedError = class extends BaseError {
|
|
1069
|
+
name = "Obligation.CollateralsAreNotSortedError";
|
|
1070
|
+
constructor() {
|
|
1071
|
+
super("Collaterals are not sorted alphabetically by address.");
|
|
1384
1072
|
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
// src/core/Offer.ts
|
|
1076
|
+
var Offer_exports = {};
|
|
1077
|
+
__export(Offer_exports, {
|
|
1078
|
+
AccountNotSetError: () => AccountNotSetError,
|
|
1079
|
+
InvalidOfferError: () => InvalidOfferError,
|
|
1080
|
+
OfferHashSchema: () => OfferHashSchema,
|
|
1081
|
+
OfferSchema: () => OfferSchema,
|
|
1082
|
+
consumedEvent: () => consumedEvent,
|
|
1083
|
+
decode: () => decode,
|
|
1084
|
+
domain: () => domain,
|
|
1085
|
+
encode: () => encode,
|
|
1086
|
+
from: () => from5,
|
|
1087
|
+
fromConsumedLog: () => fromConsumedLog,
|
|
1088
|
+
fromSnakeCase: () => fromSnakeCase3,
|
|
1089
|
+
hash: () => hash,
|
|
1090
|
+
obligationId: () => obligationId,
|
|
1091
|
+
random: () => random2,
|
|
1092
|
+
sign: () => sign,
|
|
1093
|
+
toSnakeCase: () => toSnakeCase2,
|
|
1094
|
+
types: () => types
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
// src/utils/index.ts
|
|
1098
|
+
var utils_exports = {};
|
|
1099
|
+
__export(utils_exports, {
|
|
1100
|
+
BaseError: () => BaseError,
|
|
1101
|
+
Time: () => time_exports,
|
|
1102
|
+
batch: () => batch,
|
|
1103
|
+
batchMulticall: () => batchMulticall,
|
|
1104
|
+
fromSnakeCase: () => fromSnakeCase,
|
|
1105
|
+
lazy: () => lazy,
|
|
1106
|
+
max: () => max,
|
|
1107
|
+
min: () => min,
|
|
1108
|
+
poll: () => poll,
|
|
1109
|
+
retry: () => retry,
|
|
1110
|
+
toSnakeCase: () => toSnakeCase,
|
|
1111
|
+
wait: () => wait
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1114
|
+
// src/utils/retry.ts
|
|
1115
|
+
var retry = async (fn, attempts = 3, delayMs = 50) => {
|
|
1116
|
+
let lastErr;
|
|
1117
|
+
for (let i = 0; i < attempts; i++) {
|
|
1118
|
+
try {
|
|
1119
|
+
return await fn();
|
|
1120
|
+
} catch (err) {
|
|
1121
|
+
lastErr = err;
|
|
1122
|
+
if (i < attempts - 1) await new Promise((r) => setTimeout(r, delayMs));
|
|
1123
|
+
}
|
|
1389
1124
|
}
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1125
|
+
throw lastErr;
|
|
1126
|
+
};
|
|
1127
|
+
|
|
1128
|
+
// src/utils/batchMulticall.ts
|
|
1129
|
+
async function batchMulticall(parameters) {
|
|
1130
|
+
const { client, calls, batchSize, retryAttempts, retryDelayMs, blockNumber } = parameters;
|
|
1131
|
+
const results = [];
|
|
1132
|
+
for (const callsBatch of batch(calls, batchSize)) {
|
|
1133
|
+
const batchResults = await retry(
|
|
1134
|
+
() => client.multicall({
|
|
1135
|
+
allowFailure: false,
|
|
1136
|
+
contracts: callsBatch,
|
|
1137
|
+
...blockNumber ? { blockNumber } : {}
|
|
1138
|
+
}),
|
|
1139
|
+
retryAttempts,
|
|
1140
|
+
retryDelayMs
|
|
1393
1141
|
);
|
|
1142
|
+
results.push(...batchResults);
|
|
1394
1143
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1144
|
+
return results;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// src/utils/lazy.ts
|
|
1148
|
+
function lazy(pollFn) {
|
|
1149
|
+
return () => async function* () {
|
|
1150
|
+
let active = true;
|
|
1151
|
+
let resolveNext = null;
|
|
1152
|
+
const queue = [];
|
|
1153
|
+
const wait2 = () => new Promise((resolve) => {
|
|
1154
|
+
resolveNext = resolve;
|
|
1155
|
+
});
|
|
1156
|
+
const emit = (item) => {
|
|
1157
|
+
queue.push(item);
|
|
1158
|
+
resolveNext?.();
|
|
1159
|
+
resolveNext = null;
|
|
1160
|
+
};
|
|
1161
|
+
let unpoll = null;
|
|
1162
|
+
const stop = () => {
|
|
1163
|
+
active = false;
|
|
1164
|
+
unpoll?.();
|
|
1165
|
+
resolveNext?.();
|
|
1166
|
+
resolveNext = null;
|
|
1167
|
+
};
|
|
1168
|
+
unpoll = pollFn(emit, { stop });
|
|
1169
|
+
try {
|
|
1170
|
+
while (active) {
|
|
1171
|
+
if (queue.length === 0) await wait2();
|
|
1172
|
+
while (queue.length > 0 && active) yield queue.shift();
|
|
1173
|
+
}
|
|
1174
|
+
} finally {
|
|
1175
|
+
stop();
|
|
1398
1176
|
}
|
|
1399
|
-
}
|
|
1400
|
-
return true;
|
|
1177
|
+
}();
|
|
1401
1178
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1179
|
+
|
|
1180
|
+
// src/utils/wait.ts
|
|
1181
|
+
async function wait(time) {
|
|
1182
|
+
return new Promise((res) => setTimeout(res, time));
|
|
1404
1183
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1184
|
+
|
|
1185
|
+
// src/utils/poll.ts
|
|
1186
|
+
function poll(fn, { interval }) {
|
|
1187
|
+
let active = true;
|
|
1188
|
+
const unwatch = () => active = false;
|
|
1189
|
+
const watch2 = async () => {
|
|
1190
|
+
await wait(interval);
|
|
1191
|
+
const poll2 = async () => {
|
|
1192
|
+
if (!active) return;
|
|
1193
|
+
await fn({ unpoll: unwatch });
|
|
1194
|
+
await wait(interval);
|
|
1195
|
+
poll2();
|
|
1196
|
+
};
|
|
1197
|
+
poll2();
|
|
1198
|
+
};
|
|
1199
|
+
watch2();
|
|
1200
|
+
return unwatch;
|
|
1410
1201
|
}
|
|
1411
1202
|
|
|
1412
|
-
// src/
|
|
1413
|
-
var
|
|
1414
|
-
__export(
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
generateBalancePoolId: () => generateBalancePoolId,
|
|
1418
|
-
generateBuyVaultCallbackPoolId: () => generateBuyVaultCallbackPoolId,
|
|
1419
|
-
generateDebtPoolId: () => generateDebtPoolId,
|
|
1420
|
-
generateMarketLiquidityPoolId: () => generateMarketLiquidityPoolId,
|
|
1421
|
-
generateObligationCollateralPoolId: () => generateObligationCollateralPoolId,
|
|
1422
|
-
generateSellERC20CallbackPoolId: () => generateSellERC20CallbackPoolId,
|
|
1423
|
-
generateUserVaultPositionPoolId: () => generateUserVaultPositionPoolId,
|
|
1424
|
-
generateVaultPositionPoolId: () => generateVaultPositionPoolId
|
|
1203
|
+
// src/utils/time.ts
|
|
1204
|
+
var time_exports = {};
|
|
1205
|
+
__export(time_exports, {
|
|
1206
|
+
max: () => max2,
|
|
1207
|
+
now: () => now
|
|
1425
1208
|
});
|
|
1426
|
-
function
|
|
1427
|
-
|
|
1428
|
-
const PRECISION = 10n ** 18n;
|
|
1429
|
-
const collateralQuoted = amount * oraclePrice / ORACLE_PRICE_SCALE;
|
|
1430
|
-
const maxDebt = collateralQuoted * lltv / PRECISION;
|
|
1431
|
-
return maxDebt;
|
|
1209
|
+
function now() {
|
|
1210
|
+
return Math.floor(Date.now() / 1e3);
|
|
1432
1211
|
}
|
|
1433
|
-
function
|
|
1434
|
-
|
|
1435
|
-
return `${user}-${chainId.toString()}-${token}-balance`.toLowerCase();
|
|
1436
|
-
}
|
|
1437
|
-
function generateAllowancePoolId(parameters) {
|
|
1438
|
-
const { user, chainId, token } = parameters;
|
|
1439
|
-
return `${user}-${chainId.toString()}-${token}-allowance`.toLowerCase();
|
|
1440
|
-
}
|
|
1441
|
-
function generateSellERC20CallbackPoolId(parameters) {
|
|
1442
|
-
const { user, chainId, obligationId: obligationId2, token, offerHash } = parameters;
|
|
1443
|
-
return `${user}-${chainId.toString()}-${obligationId2}-${token}-${offerHash}-sell_erc20_callback`.toLowerCase();
|
|
1444
|
-
}
|
|
1445
|
-
function generateObligationCollateralPoolId(parameters) {
|
|
1446
|
-
const { user, chainId, obligationId: obligationId2, token } = parameters;
|
|
1447
|
-
return `${user}-${chainId.toString()}-${obligationId2}-${token}-obligation-collateral`.toLowerCase();
|
|
1448
|
-
}
|
|
1449
|
-
function generateBuyVaultCallbackPoolId(parameters) {
|
|
1450
|
-
const { user, chainId, vault, offerHash } = parameters;
|
|
1451
|
-
return `${user}-${chainId.toString()}-${vault}-${offerHash}-${"buy_vault_v1_callback" /* BuyVaultV1Callback */}`.toLowerCase();
|
|
1452
|
-
}
|
|
1453
|
-
function generateDebtPoolId(parameters) {
|
|
1454
|
-
const { user, chainId, obligationId: obligationId2 } = parameters;
|
|
1455
|
-
return `${user}-${chainId.toString()}-${obligationId2}-debt`.toLowerCase();
|
|
1456
|
-
}
|
|
1457
|
-
function generateUserVaultPositionPoolId(parameters) {
|
|
1458
|
-
const { user, chainId, vault } = parameters;
|
|
1459
|
-
return `${user}-${chainId.toString()}-${vault}-user-vault-position`.toLowerCase();
|
|
1460
|
-
}
|
|
1461
|
-
function generateVaultPositionPoolId(parameters) {
|
|
1462
|
-
const { vault, chainId, marketId } = parameters;
|
|
1463
|
-
return `${vault}-${chainId.toString()}-${marketId}-vault-position`.toLowerCase();
|
|
1464
|
-
}
|
|
1465
|
-
function generateMarketLiquidityPoolId(parameters) {
|
|
1466
|
-
const { chainId, marketId } = parameters;
|
|
1467
|
-
return `${chainId.toString()}-${marketId}-market-liquidity`.toLowerCase();
|
|
1212
|
+
function max2() {
|
|
1213
|
+
return 864e16;
|
|
1468
1214
|
}
|
|
1469
1215
|
|
|
1470
|
-
// src/core/
|
|
1471
|
-
var
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
).transform((
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
if (typeof ts === "string") {
|
|
1509
|
-
if (ts in MaturityOptions) return MaturityOptions[ts]();
|
|
1510
|
-
throw new InvalidOptionError2(ts);
|
|
1511
|
-
}
|
|
1512
|
-
if (typeof ts === "number" && ts > 1e12) throw new InvalidFormatError();
|
|
1513
|
-
if (!Object.values(MaturityOptions).some((option) => option() === ts))
|
|
1514
|
-
throw new InvalidDateError(ts);
|
|
1515
|
-
return ts;
|
|
1516
|
-
}
|
|
1517
|
-
var endOfWeek = () => fridayOfWeek(0);
|
|
1518
|
-
var endOfNextWeek = () => fridayOfWeek(1);
|
|
1519
|
-
var endOfMonth = () => lastFridayOfMonth((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth());
|
|
1520
|
-
var endOfNextMonth = () => lastFridayOfMonth((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth() + 1);
|
|
1521
|
-
var endOfQuarter = () => lastFridayOfQuarter(0);
|
|
1522
|
-
var endOfNextQuarter = () => lastFridayOfQuarter(1);
|
|
1523
|
-
var fridayOfWeek = (weeksAhead = 0) => {
|
|
1524
|
-
const now2 = /* @__PURE__ */ new Date();
|
|
1525
|
-
const today15H = new Date(
|
|
1526
|
-
Date.UTC(now2.getUTCFullYear(), now2.getUTCMonth(), now2.getUTCDate(), 15)
|
|
1527
|
-
);
|
|
1528
|
-
let daysUntilFriday = (5 - today15H.getUTCDay() + 7) % 7;
|
|
1529
|
-
if (daysUntilFriday === 0 && now2.getTime() >= today15H.getTime()) {
|
|
1530
|
-
daysUntilFriday = 7;
|
|
1531
|
-
}
|
|
1532
|
-
const friday = new Date(today15H);
|
|
1533
|
-
friday.setUTCDate(friday.getUTCDate() + daysUntilFriday + weeksAhead * 7);
|
|
1534
|
-
return friday.getTime() / 1e3;
|
|
1535
|
-
};
|
|
1536
|
-
var lastFridayOfMonth = (year, month) => {
|
|
1537
|
-
const lastDayOfMonth15H = new Date(Date.UTC(year, month + 1, 0, 15));
|
|
1538
|
-
while (lastDayOfMonth15H.getUTCDay() !== 5) {
|
|
1539
|
-
lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate() - 1);
|
|
1540
|
-
}
|
|
1541
|
-
const maturity = lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate()) / 1e3;
|
|
1542
|
-
return maturity;
|
|
1543
|
-
};
|
|
1544
|
-
var lastFridayOfQuarter = (quartersAhead = 0) => {
|
|
1545
|
-
const now2 = /* @__PURE__ */ new Date();
|
|
1546
|
-
const quarterIndex = Math.floor(now2.getUTCMonth() / 3) + quartersAhead;
|
|
1547
|
-
const year = now2.getUTCFullYear() + Math.floor(quarterIndex / 4);
|
|
1548
|
-
const quarter = quarterIndex % 4;
|
|
1549
|
-
const lastMonth = quarter * 3 + 2;
|
|
1550
|
-
return lastFridayOfMonth(year, lastMonth);
|
|
1551
|
-
};
|
|
1552
|
-
var InvalidFormatError = class extends BaseError {
|
|
1553
|
-
name = "Maturity.InvalidFormatError";
|
|
1554
|
-
constructor() {
|
|
1555
|
-
super("Invalid maturity format. Maturity should be expressed in seconds.");
|
|
1556
|
-
}
|
|
1557
|
-
};
|
|
1558
|
-
var InvalidDateError = class extends BaseError {
|
|
1559
|
-
name = "Maturity.InvalidDateError";
|
|
1560
|
-
constructor(input) {
|
|
1561
|
-
super(
|
|
1562
|
-
`Invalid maturity date. Input: "${input}". Accepted values are: ${Object.values(
|
|
1563
|
-
MaturityOptions
|
|
1564
|
-
).map((option) => `"${option()}"`).join(", ")}.`
|
|
1565
|
-
);
|
|
1566
|
-
}
|
|
1567
|
-
};
|
|
1568
|
-
var InvalidOptionError2 = class extends BaseError {
|
|
1569
|
-
name = "Maturity.InvalidOptionError";
|
|
1570
|
-
constructor(input) {
|
|
1571
|
-
super(
|
|
1572
|
-
`Invalid maturity option. Input: "${input}". Accepted values are: ${Object.keys(
|
|
1573
|
-
MaturityOptions
|
|
1574
|
-
).map((option) => `"${option}"`).join(", ")}.`
|
|
1575
|
-
);
|
|
1576
|
-
}
|
|
1216
|
+
// src/core/Offer.ts
|
|
1217
|
+
var OfferHashSchema = z6.string().regex(/^0x[0-9a-fA-F]{64}$/, {
|
|
1218
|
+
message: "Hash must be a valid 32-byte hex string"
|
|
1219
|
+
}).transform(transformHex);
|
|
1220
|
+
var OfferSchema = (parameters) => {
|
|
1221
|
+
const { omitHash = false } = parameters || {};
|
|
1222
|
+
const now2 = time_exports.now();
|
|
1223
|
+
let base = z6.object({
|
|
1224
|
+
offering: z6.string().transform(transformAddress),
|
|
1225
|
+
assets: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1226
|
+
rate: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1227
|
+
maturity: MaturitySchema,
|
|
1228
|
+
expiry: z6.number().int().min(now2, { message: "Expiry must be set to a future date" }).max(Number.MAX_SAFE_INTEGER),
|
|
1229
|
+
start: z6.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
1230
|
+
nonce: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1231
|
+
buy: z6.boolean(),
|
|
1232
|
+
chainId: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1233
|
+
loanToken: z6.string().transform(transformAddress),
|
|
1234
|
+
collaterals: CollateralsSchema,
|
|
1235
|
+
callback: z6.object({
|
|
1236
|
+
address: z6.string().transform(transformAddress),
|
|
1237
|
+
data: z6.string().transform(transformHex),
|
|
1238
|
+
gasLimit: z6.bigint({ coerce: true }).min(0n).max(maxUint256)
|
|
1239
|
+
}),
|
|
1240
|
+
consumed: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1241
|
+
blockNumber: z6.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
1242
|
+
signature: z6.string().regex(/^0x[0-9a-fA-F]{130}$/, {
|
|
1243
|
+
message: "Signature must be a valid 65-byte hex string"
|
|
1244
|
+
}).transform(transformHex).optional()
|
|
1245
|
+
});
|
|
1246
|
+
if (!omitHash) base = base.extend({ hash: OfferHashSchema });
|
|
1247
|
+
return base.refine((data) => data.start < data.expiry, {
|
|
1248
|
+
message: "Start must be before expiry",
|
|
1249
|
+
path: ["start"]
|
|
1250
|
+
}).refine((data) => data.expiry <= data.maturity, {
|
|
1251
|
+
message: "Expiry cannot be after maturity",
|
|
1252
|
+
path: ["expiry"]
|
|
1253
|
+
});
|
|
1577
1254
|
};
|
|
1578
|
-
|
|
1579
|
-
// src/core/Obligation.ts
|
|
1580
|
-
var Obligation_exports = {};
|
|
1581
|
-
__export(Obligation_exports, {
|
|
1582
|
-
CollateralsAreNotSortedError: () => CollateralsAreNotSortedError,
|
|
1583
|
-
InvalidObligationError: () => InvalidObligationError,
|
|
1584
|
-
ObligationSchema: () => ObligationSchema,
|
|
1585
|
-
from: () => from4,
|
|
1586
|
-
fromSnakeCase: () => fromSnakeCase2,
|
|
1587
|
-
id: () => id,
|
|
1588
|
-
random: () => random
|
|
1589
|
-
});
|
|
1590
|
-
var ObligationSchema = z6.object({
|
|
1591
|
-
chainId: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1592
|
-
loanToken: z6.string().transform(transformAddress),
|
|
1593
|
-
collaterals: CollateralsSchema,
|
|
1594
|
-
maturity: MaturitySchema
|
|
1595
|
-
});
|
|
1596
|
-
function from4(parameters) {
|
|
1255
|
+
function from5(input) {
|
|
1597
1256
|
try {
|
|
1598
|
-
const
|
|
1599
|
-
|
|
1600
|
-
maturity: from3(parameters.maturity)
|
|
1601
|
-
});
|
|
1257
|
+
const parsedOffer = OfferSchema({ omitHash: true }).parse(input);
|
|
1258
|
+
const parsedHash = OfferHashSchema.parse(hash(parsedOffer));
|
|
1602
1259
|
return {
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
collaterals: parsedObligation.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)),
|
|
1606
|
-
maturity: parsedObligation.maturity
|
|
1260
|
+
...parsedOffer,
|
|
1261
|
+
hash: parsedHash
|
|
1607
1262
|
};
|
|
1608
1263
|
} catch (error2) {
|
|
1609
|
-
throw new
|
|
1264
|
+
throw new InvalidOfferError(error2);
|
|
1610
1265
|
}
|
|
1611
1266
|
}
|
|
1612
|
-
function
|
|
1613
|
-
return
|
|
1267
|
+
function fromSnakeCase3(input) {
|
|
1268
|
+
return from5(fromSnakeCase(input));
|
|
1614
1269
|
}
|
|
1615
|
-
function
|
|
1616
|
-
|
|
1617
|
-
for (const collateral of obligation.collaterals) {
|
|
1618
|
-
const newAsset = collateral.asset.toLowerCase();
|
|
1619
|
-
if (newAsset.localeCompare(lastAsset) < 0) throw new CollateralsAreNotSortedError();
|
|
1620
|
-
lastAsset = newAsset;
|
|
1621
|
-
}
|
|
1622
|
-
return keccak256(
|
|
1623
|
-
encodeAbiParameters(
|
|
1624
|
-
[
|
|
1625
|
-
{ type: "uint256" },
|
|
1626
|
-
{ type: "address" },
|
|
1627
|
-
{
|
|
1628
|
-
type: "tuple[]",
|
|
1629
|
-
components: [
|
|
1630
|
-
{ type: "address", name: "token" },
|
|
1631
|
-
{ type: "uint256", name: "lltv" },
|
|
1632
|
-
{ type: "address", name: "oracle" }
|
|
1633
|
-
]
|
|
1634
|
-
},
|
|
1635
|
-
{ type: "uint256" }
|
|
1636
|
-
],
|
|
1637
|
-
[
|
|
1638
|
-
obligation.chainId,
|
|
1639
|
-
obligation.loanToken.toLowerCase(),
|
|
1640
|
-
obligation.collaterals.map((c) => ({
|
|
1641
|
-
token: c.asset.toLowerCase(),
|
|
1642
|
-
lltv: c.lltv,
|
|
1643
|
-
oracle: c.oracle.toLowerCase()
|
|
1644
|
-
})),
|
|
1645
|
-
BigInt(obligation.maturity)
|
|
1646
|
-
]
|
|
1647
|
-
)
|
|
1648
|
-
);
|
|
1270
|
+
function toSnakeCase2(offer) {
|
|
1271
|
+
return toSnakeCase(offer);
|
|
1649
1272
|
}
|
|
1650
|
-
function
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
})
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
const now2 = time_exports.now();
|
|
1704
|
-
let base = z6.object({
|
|
1705
|
-
offering: z6.string().transform(transformAddress),
|
|
1706
|
-
assets: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1707
|
-
rate: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1708
|
-
maturity: MaturitySchema,
|
|
1709
|
-
expiry: z6.number().int().min(now2, { message: "Expiry must be set to a future date" }).max(Number.MAX_SAFE_INTEGER),
|
|
1710
|
-
start: z6.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
1711
|
-
nonce: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1712
|
-
buy: z6.boolean(),
|
|
1713
|
-
chainId: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1714
|
-
loanToken: z6.string().transform(transformAddress),
|
|
1715
|
-
collaterals: CollateralsSchema,
|
|
1716
|
-
callback: z6.object({
|
|
1717
|
-
address: z6.string().transform(transformAddress),
|
|
1718
|
-
data: z6.string().transform(transformHex),
|
|
1719
|
-
gasLimit: z6.bigint({ coerce: true }).min(0n).max(maxUint256)
|
|
1720
|
-
}),
|
|
1721
|
-
consumed: z6.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1722
|
-
blockNumber: z6.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
1723
|
-
signature: z6.string().regex(/^0x[0-9a-fA-F]{130}$/, {
|
|
1724
|
-
message: "Signature must be a valid 65-byte hex string"
|
|
1725
|
-
}).transform(transformHex).optional()
|
|
1726
|
-
});
|
|
1727
|
-
if (!omitHash) base = base.extend({ hash: OfferHashSchema });
|
|
1728
|
-
return base.refine((data) => data.start < data.expiry, {
|
|
1729
|
-
message: "Start must be before expiry",
|
|
1730
|
-
path: ["start"]
|
|
1731
|
-
}).refine((data) => data.expiry <= data.maturity, {
|
|
1732
|
-
message: "Expiry cannot be after maturity",
|
|
1733
|
-
path: ["expiry"]
|
|
1734
|
-
});
|
|
1735
|
-
};
|
|
1736
|
-
function from5(input) {
|
|
1737
|
-
try {
|
|
1738
|
-
const parsedOffer = OfferSchema({ omitHash: true }).parse(input);
|
|
1739
|
-
const parsedHash = OfferHashSchema.parse(hash(parsedOffer));
|
|
1740
|
-
return {
|
|
1741
|
-
...parsedOffer,
|
|
1742
|
-
hash: parsedHash
|
|
1743
|
-
};
|
|
1744
|
-
} catch (error2) {
|
|
1745
|
-
throw new InvalidOfferError(error2);
|
|
1746
|
-
}
|
|
1747
|
-
}
|
|
1748
|
-
function fromSnakeCase3(input) {
|
|
1749
|
-
return from5(fromSnakeCase(input));
|
|
1750
|
-
}
|
|
1751
|
-
function toSnakeCase2(offer) {
|
|
1752
|
-
return toSnakeCase(offer);
|
|
1753
|
-
}
|
|
1754
|
-
function random2() {
|
|
1755
|
-
const loanToken = privateKeyToAccount(generatePrivateKey()).address;
|
|
1756
|
-
const maturity = from3("end_of_month");
|
|
1757
|
-
const expiry = from3("end_of_week") - 1;
|
|
1758
|
-
const lltv = from(0.965);
|
|
1273
|
+
function random2(config) {
|
|
1274
|
+
const chain = config?.chains ? config.chains[Math.floor(Math.random() * config.chains.length)] : chains.ethereum;
|
|
1275
|
+
const loanToken = config?.loanTokens ? config.loanTokens[Math.floor(Math.random() * config.loanTokens.length)] : privateKeyToAccount(generatePrivateKey()).address;
|
|
1276
|
+
const collateralCandidates = config?.collateralTokens ? config.collateralTokens.filter((a) => a !== loanToken) : [privateKeyToAccount(generatePrivateKey()).address];
|
|
1277
|
+
const collateralAsset = collateralCandidates[Math.floor(Math.random() * collateralCandidates.length)];
|
|
1278
|
+
const maturityOption = weightedChoice([
|
|
1279
|
+
["end_of_month", 1],
|
|
1280
|
+
["end_of_next_month", 1]
|
|
1281
|
+
]);
|
|
1282
|
+
const maturity = config?.maturity ?? from3(maturityOption);
|
|
1283
|
+
const lltv = from(
|
|
1284
|
+
weightedChoice([
|
|
1285
|
+
[0.385, 1],
|
|
1286
|
+
[0.5, 1],
|
|
1287
|
+
[0.625, 2],
|
|
1288
|
+
[0.77, 8],
|
|
1289
|
+
[0.86, 10],
|
|
1290
|
+
[0.915, 8],
|
|
1291
|
+
[0.945, 6],
|
|
1292
|
+
[0.965, 4],
|
|
1293
|
+
[0.98, 2]
|
|
1294
|
+
])
|
|
1295
|
+
);
|
|
1296
|
+
const buy = config?.buy !== void 0 ? config.buy : Math.random() > 0.5;
|
|
1297
|
+
const ONE = 1000000000000000000n;
|
|
1298
|
+
const qMin = buy ? 16 : 4;
|
|
1299
|
+
const qMax = buy ? 32 : 16;
|
|
1300
|
+
const len = qMax - qMin + 1;
|
|
1301
|
+
const ratePairs = Array.from(
|
|
1302
|
+
{ length: len },
|
|
1303
|
+
(_, idx) => {
|
|
1304
|
+
const q = qMin + idx;
|
|
1305
|
+
const scaledRate = BigInt(q) * (ONE / 4n);
|
|
1306
|
+
const weight = buy ? 1 + idx : 1 + (len - 1 - idx);
|
|
1307
|
+
return [scaledRate, weight];
|
|
1308
|
+
}
|
|
1309
|
+
);
|
|
1310
|
+
const rate = config?.rate ?? weightedChoice(ratePairs);
|
|
1311
|
+
const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
|
|
1312
|
+
const unit = BigInt(10) ** BigInt(loanTokenDecimals);
|
|
1313
|
+
const amountBase = BigInt(100 + Math.floor(Math.random() * (1e6 - 100 + 1)));
|
|
1314
|
+
const assetsScaled = config?.assets ?? amountBase * unit;
|
|
1315
|
+
const consumed2 = config?.consumed !== void 0 ? config.consumed : Math.random() < 0.8 ? 0n : assetsScaled * BigInt(1 + Math.floor(Math.random() * 900)) / 1000n;
|
|
1316
|
+
const callbackBySide = (() => {
|
|
1317
|
+
if (buy) return { address: zeroAddress, data: "0x", gasLimit: 0n };
|
|
1318
|
+
const sellCallbackAddress = WhitelistedCallbackAddresses["sell_erc20_callback" /* SellERC20Callback */][0].toLowerCase();
|
|
1319
|
+
const amount = assetsScaled * 1000000000000000000000n;
|
|
1320
|
+
const data = encodeSellERC20Callback({
|
|
1321
|
+
collaterals: [collateralAsset],
|
|
1322
|
+
amounts: [amount]
|
|
1323
|
+
});
|
|
1324
|
+
return { address: sellCallbackAddress, data, gasLimit: 500000n };
|
|
1325
|
+
})();
|
|
1759
1326
|
const offer = from5({
|
|
1760
|
-
offering: privateKeyToAccount(generatePrivateKey()).address,
|
|
1761
|
-
assets:
|
|
1762
|
-
rate
|
|
1327
|
+
offering: config?.offering ?? privateKeyToAccount(generatePrivateKey()).address,
|
|
1328
|
+
assets: assetsScaled,
|
|
1329
|
+
rate,
|
|
1763
1330
|
maturity,
|
|
1764
|
-
expiry,
|
|
1765
|
-
start:
|
|
1331
|
+
expiry: config?.expiry ?? maturity - 1,
|
|
1332
|
+
start: config?.start ?? maturity - 10,
|
|
1766
1333
|
nonce: BigInt(Math.floor(Math.random() * 1e6)),
|
|
1767
|
-
buy
|
|
1768
|
-
chainId:
|
|
1334
|
+
buy,
|
|
1335
|
+
chainId: chain.id,
|
|
1769
1336
|
loanToken,
|
|
1770
|
-
collaterals: [
|
|
1337
|
+
collaterals: config?.collaterals ?? [
|
|
1771
1338
|
from2({
|
|
1772
|
-
asset:
|
|
1339
|
+
asset: collateralAsset,
|
|
1773
1340
|
oracle: zeroAddress,
|
|
1774
1341
|
lltv
|
|
1775
1342
|
})
|
|
1776
1343
|
],
|
|
1777
|
-
callback:
|
|
1778
|
-
|
|
1779
|
-
data: "0x",
|
|
1780
|
-
gasLimit: 0n
|
|
1781
|
-
},
|
|
1782
|
-
consumed: 0n,
|
|
1344
|
+
callback: config?.callback ?? callbackBySide,
|
|
1345
|
+
consumed: consumed2,
|
|
1783
1346
|
blockNumber: Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
|
|
1784
1347
|
});
|
|
1785
1348
|
return offer;
|
|
1786
1349
|
}
|
|
1350
|
+
var weightedChoice = (pairs) => {
|
|
1351
|
+
const total = pairs.reduce((sum, [, weight]) => sum + weight, 0);
|
|
1352
|
+
let roll = Math.random() * total;
|
|
1353
|
+
for (const [value, weight] of pairs) {
|
|
1354
|
+
roll -= weight;
|
|
1355
|
+
if (roll < 0) return value;
|
|
1356
|
+
}
|
|
1357
|
+
return pairs[0][0];
|
|
1358
|
+
};
|
|
1787
1359
|
var domain = (chainId) => ({
|
|
1788
1360
|
chainId,
|
|
1789
1361
|
verifyingContract: zeroAddress
|
|
@@ -1839,166 +1411,1084 @@ function sign(offer, wallet) {
|
|
|
1839
1411
|
gasLimit: offer.callback.gasLimit
|
|
1840
1412
|
}
|
|
1841
1413
|
}
|
|
1842
|
-
});
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
function hash(offer) {
|
|
1417
|
+
return hashTypedData({
|
|
1418
|
+
domain: domain(offer.chainId),
|
|
1419
|
+
message: {
|
|
1420
|
+
offering: offer.offering.toLowerCase(),
|
|
1421
|
+
assets: offer.assets,
|
|
1422
|
+
rate: offer.rate,
|
|
1423
|
+
maturity: BigInt(offer.maturity),
|
|
1424
|
+
expiry: BigInt(offer.expiry),
|
|
1425
|
+
nonce: offer.nonce,
|
|
1426
|
+
buy: offer.buy,
|
|
1427
|
+
loanToken: offer.loanToken.toLowerCase(),
|
|
1428
|
+
collaterals: offer.collaterals,
|
|
1429
|
+
callback: {
|
|
1430
|
+
address: offer.callback.address.toLowerCase(),
|
|
1431
|
+
data: offer.callback.data,
|
|
1432
|
+
gasLimit: offer.callback.gasLimit
|
|
1433
|
+
}
|
|
1434
|
+
},
|
|
1435
|
+
primaryType: "Offer",
|
|
1436
|
+
types
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
function obligationId(offer) {
|
|
1440
|
+
return id(
|
|
1441
|
+
from4({
|
|
1442
|
+
chainId: offer.chainId,
|
|
1443
|
+
loanToken: offer.loanToken,
|
|
1444
|
+
collaterals: offer.collaterals,
|
|
1445
|
+
maturity: offer.maturity
|
|
1446
|
+
})
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
var OfferAbi = [
|
|
1450
|
+
{ name: "offering", type: "address" },
|
|
1451
|
+
{ name: "assets", type: "uint256" },
|
|
1452
|
+
{ name: "rate", type: "uint256" },
|
|
1453
|
+
{ name: "maturity", type: "uint256" },
|
|
1454
|
+
{ name: "expiry", type: "uint256" },
|
|
1455
|
+
{ name: "nonce", type: "uint256" },
|
|
1456
|
+
{ name: "buy", type: "bool" },
|
|
1457
|
+
{ name: "chainId", type: "uint256" },
|
|
1458
|
+
{ name: "loanToken", type: "address" },
|
|
1459
|
+
{ name: "start", type: "uint256" },
|
|
1460
|
+
{
|
|
1461
|
+
name: "collaterals",
|
|
1462
|
+
type: "tuple[]",
|
|
1463
|
+
components: [
|
|
1464
|
+
{ name: "asset", type: "address" },
|
|
1465
|
+
{ name: "oracle", type: "address" },
|
|
1466
|
+
{ name: "lltv", type: "uint256" }
|
|
1467
|
+
]
|
|
1468
|
+
},
|
|
1469
|
+
{
|
|
1470
|
+
name: "callback",
|
|
1471
|
+
type: "tuple",
|
|
1472
|
+
components: [
|
|
1473
|
+
{ name: "address", type: "address" },
|
|
1474
|
+
{ name: "data", type: "bytes" },
|
|
1475
|
+
{ name: "gasLimit", type: "uint256" }
|
|
1476
|
+
]
|
|
1477
|
+
},
|
|
1478
|
+
{ name: "signature", type: "bytes" }
|
|
1479
|
+
];
|
|
1480
|
+
function encode(offer) {
|
|
1481
|
+
return encodeAbiParameters(OfferAbi, [
|
|
1482
|
+
offer.offering,
|
|
1483
|
+
offer.assets,
|
|
1484
|
+
offer.rate,
|
|
1485
|
+
BigInt(offer.maturity),
|
|
1486
|
+
BigInt(offer.expiry),
|
|
1487
|
+
offer.nonce,
|
|
1488
|
+
offer.buy,
|
|
1489
|
+
offer.chainId,
|
|
1490
|
+
offer.loanToken,
|
|
1491
|
+
BigInt(offer.start),
|
|
1492
|
+
offer.collaterals,
|
|
1493
|
+
offer.callback,
|
|
1494
|
+
offer.signature ?? "0x"
|
|
1495
|
+
]);
|
|
1496
|
+
}
|
|
1497
|
+
function decode(data, blockNumber) {
|
|
1498
|
+
let decoded;
|
|
1499
|
+
try {
|
|
1500
|
+
decoded = decodeAbiParameters(OfferAbi, data);
|
|
1501
|
+
} catch (error2) {
|
|
1502
|
+
throw new InvalidOfferError(error2);
|
|
1503
|
+
}
|
|
1504
|
+
const offer = from5({
|
|
1505
|
+
offering: decoded[0],
|
|
1506
|
+
assets: decoded[1],
|
|
1507
|
+
rate: decoded[2],
|
|
1508
|
+
maturity: from3(Number(decoded[3])),
|
|
1509
|
+
expiry: Number(decoded[4]),
|
|
1510
|
+
nonce: decoded[5],
|
|
1511
|
+
buy: decoded[6],
|
|
1512
|
+
chainId: decoded[7],
|
|
1513
|
+
loanToken: decoded[8],
|
|
1514
|
+
start: Number(decoded[9]),
|
|
1515
|
+
collaterals: decoded[10].map((c) => {
|
|
1516
|
+
return from2({
|
|
1517
|
+
asset: c.asset,
|
|
1518
|
+
oracle: c.oracle,
|
|
1519
|
+
lltv: c.lltv
|
|
1520
|
+
});
|
|
1521
|
+
}),
|
|
1522
|
+
callback: {
|
|
1523
|
+
address: decoded[11].address,
|
|
1524
|
+
data: decoded[11].data,
|
|
1525
|
+
gasLimit: decoded[11].gasLimit
|
|
1526
|
+
},
|
|
1527
|
+
consumed: 0n,
|
|
1528
|
+
blockNumber: Number(blockNumber),
|
|
1529
|
+
...decoded[12] === "0x" ? {} : { signature: decoded[12] }
|
|
1530
|
+
});
|
|
1531
|
+
return offer;
|
|
1532
|
+
}
|
|
1533
|
+
var consumedEvent = {
|
|
1534
|
+
type: "event",
|
|
1535
|
+
name: "Consumed",
|
|
1536
|
+
inputs: [
|
|
1537
|
+
{ name: "user", type: "address", indexed: true, internalType: "address" },
|
|
1538
|
+
{ name: "nonce", type: "uint256", indexed: true, internalType: "uint256" },
|
|
1539
|
+
{ name: "amount", type: "uint256", indexed: false, internalType: "uint256" }
|
|
1540
|
+
],
|
|
1541
|
+
anonymous: false
|
|
1542
|
+
};
|
|
1543
|
+
function fromConsumedLog(parameters) {
|
|
1544
|
+
const { blockNumber, logIndex, chainId, transactionHash, user, nonce, amount } = parameters;
|
|
1545
|
+
return {
|
|
1546
|
+
id: `${blockNumber.toString()}-${logIndex.toString()}-${chainId}-${transactionHash}`,
|
|
1547
|
+
chainId: BigInt(chainId),
|
|
1548
|
+
offering: user,
|
|
1549
|
+
nonce,
|
|
1550
|
+
amount,
|
|
1551
|
+
blockNumber: Number(blockNumber)
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1554
|
+
var InvalidOfferError = class extends BaseError {
|
|
1555
|
+
name = "Offer.InvalidOfferError";
|
|
1556
|
+
constructor(error2) {
|
|
1557
|
+
super("Invalid offer.", { cause: error2 });
|
|
1558
|
+
}
|
|
1559
|
+
};
|
|
1560
|
+
var AccountNotSetError = class extends BaseError {
|
|
1561
|
+
name = "Offer.AccountNotSetError";
|
|
1562
|
+
constructor() {
|
|
1563
|
+
super("Account not set.");
|
|
1564
|
+
}
|
|
1565
|
+
};
|
|
1566
|
+
|
|
1567
|
+
// src/core/Quote.ts
|
|
1568
|
+
var Quote_exports = {};
|
|
1569
|
+
__export(Quote_exports, {
|
|
1570
|
+
InvalidQuoteError: () => InvalidQuoteError,
|
|
1571
|
+
QuoteSchema: () => QuoteSchema,
|
|
1572
|
+
from: () => from6,
|
|
1573
|
+
fromSnakeCase: () => fromSnakeCase4,
|
|
1574
|
+
random: () => random3
|
|
1575
|
+
});
|
|
1576
|
+
var QuoteSchema = z6.object({
|
|
1577
|
+
obligationId: z6.string().transform(transformHex),
|
|
1578
|
+
ask: z6.object({
|
|
1579
|
+
rate: z6.bigint({ coerce: true }).min(0n).max(maxUint256)
|
|
1580
|
+
}),
|
|
1581
|
+
bid: z6.object({
|
|
1582
|
+
rate: z6.bigint({ coerce: true }).min(0n).max(maxUint256)
|
|
1583
|
+
})
|
|
1584
|
+
});
|
|
1585
|
+
function from6(parameters) {
|
|
1586
|
+
try {
|
|
1587
|
+
const parsedQuote = QuoteSchema.parse(parameters);
|
|
1588
|
+
return {
|
|
1589
|
+
obligationId: parsedQuote.obligationId,
|
|
1590
|
+
ask: parsedQuote.ask,
|
|
1591
|
+
bid: parsedQuote.bid
|
|
1592
|
+
};
|
|
1593
|
+
} catch (error2) {
|
|
1594
|
+
throw new InvalidQuoteError(error2);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
function fromSnakeCase4(snake) {
|
|
1598
|
+
return from6(fromSnakeCase(snake));
|
|
1599
|
+
}
|
|
1600
|
+
function random3() {
|
|
1601
|
+
return from6({
|
|
1602
|
+
obligationId: Obligation_exports.id(Obligation_exports.random()),
|
|
1603
|
+
ask: {
|
|
1604
|
+
rate: BigInt(Math.floor(Math.random() * 1e6))
|
|
1605
|
+
},
|
|
1606
|
+
bid: {
|
|
1607
|
+
rate: BigInt(Math.floor(Math.random() * 1e6))
|
|
1608
|
+
}
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
var InvalidQuoteError = class extends BaseError {
|
|
1612
|
+
name = "Quote.InvalidQuoteError";
|
|
1613
|
+
constructor(error2) {
|
|
1614
|
+
super("Invalid quote.", { cause: error2 });
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
|
|
1618
|
+
// src/core/types.ts
|
|
1619
|
+
var BrandTypeId = Symbol.for("mempool/Brand");
|
|
1620
|
+
var CollectorHealth = z.object({
|
|
1621
|
+
name: z.string(),
|
|
1622
|
+
chain_id: z.number(),
|
|
1623
|
+
block_number: z.number().nullable(),
|
|
1624
|
+
updated_at: z.string().nullable(),
|
|
1625
|
+
lag: z.number().nullable(),
|
|
1626
|
+
status: z.enum(["live", "lagging", "unknown"])
|
|
1627
|
+
});
|
|
1628
|
+
var CollectorsHealthResponse = z.array(CollectorHealth);
|
|
1629
|
+
var ChainHealth = z.object({
|
|
1630
|
+
chain_id: z.number(),
|
|
1631
|
+
block_number: z.number(),
|
|
1632
|
+
updated_at: z.string()
|
|
1633
|
+
});
|
|
1634
|
+
var ChainsHealthResponse = z.array(ChainHealth);
|
|
1635
|
+
var RouterStatusResponse = z.object({
|
|
1636
|
+
status: z.enum(["live", "syncing"])
|
|
1637
|
+
});
|
|
1638
|
+
|
|
1639
|
+
// src/stores/utils/Cursor.ts
|
|
1640
|
+
var Cursor_exports = {};
|
|
1641
|
+
__export(Cursor_exports, {
|
|
1642
|
+
decode: () => decode2,
|
|
1643
|
+
encode: () => encode2,
|
|
1644
|
+
validate: () => validate
|
|
1645
|
+
});
|
|
1646
|
+
function validate(cursor) {
|
|
1647
|
+
if (!cursor || typeof cursor !== "object") {
|
|
1648
|
+
throw new Error("Cursor must be an object");
|
|
1649
|
+
}
|
|
1650
|
+
const c = cursor;
|
|
1651
|
+
if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
|
|
1652
|
+
throw new Error(
|
|
1653
|
+
`Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
if (!["asc", "desc"].includes(c.dir)) {
|
|
1657
|
+
throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
|
|
1658
|
+
}
|
|
1659
|
+
if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
|
|
1660
|
+
throw new Error(
|
|
1661
|
+
`Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
|
|
1662
|
+
);
|
|
1663
|
+
}
|
|
1664
|
+
const validations = {
|
|
1665
|
+
rate: {
|
|
1666
|
+
field: "rate",
|
|
1667
|
+
type: "string",
|
|
1668
|
+
pattern: /^\d+$/,
|
|
1669
|
+
error: "numeric string"
|
|
1670
|
+
},
|
|
1671
|
+
amount: {
|
|
1672
|
+
field: "assets",
|
|
1673
|
+
type: "string",
|
|
1674
|
+
pattern: /^\d+$/,
|
|
1675
|
+
error: "numeric string"
|
|
1676
|
+
},
|
|
1677
|
+
maturity: {
|
|
1678
|
+
field: "maturity",
|
|
1679
|
+
type: "number",
|
|
1680
|
+
validator: (val) => val > 0,
|
|
1681
|
+
error: "positive number"
|
|
1682
|
+
},
|
|
1683
|
+
expiry: {
|
|
1684
|
+
field: "expiry",
|
|
1685
|
+
type: "number",
|
|
1686
|
+
validator: (val) => val > 0,
|
|
1687
|
+
error: "positive number"
|
|
1688
|
+
}
|
|
1689
|
+
};
|
|
1690
|
+
const validation = validations[c.sort];
|
|
1691
|
+
if (!validation) {
|
|
1692
|
+
throw new Error(`Invalid sort field: ${c.sort}`);
|
|
1693
|
+
}
|
|
1694
|
+
const fieldValue = c[validation.field];
|
|
1695
|
+
if (!fieldValue) {
|
|
1696
|
+
throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
|
|
1697
|
+
}
|
|
1698
|
+
if (typeof fieldValue !== validation.type) {
|
|
1699
|
+
throw new Error(
|
|
1700
|
+
`${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
|
|
1701
|
+
);
|
|
1702
|
+
}
|
|
1703
|
+
if (validation.pattern && !validation.pattern.test(fieldValue)) {
|
|
1704
|
+
throw new Error(
|
|
1705
|
+
`Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
if (validation.validator && !validation.validator(fieldValue)) {
|
|
1709
|
+
throw new Error(
|
|
1710
|
+
`Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
|
|
1711
|
+
);
|
|
1712
|
+
}
|
|
1713
|
+
if (c.page !== void 0) {
|
|
1714
|
+
if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
|
|
1715
|
+
throw new Error("Invalid page: must be a positive integer");
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
return true;
|
|
1719
|
+
}
|
|
1720
|
+
function encode2(c) {
|
|
1721
|
+
return Base64.encodeURL(JSON.stringify(c));
|
|
1722
|
+
}
|
|
1723
|
+
function decode2(token) {
|
|
1724
|
+
if (!token) return null;
|
|
1725
|
+
const decoded = JSON.parse(Base64.decode(token));
|
|
1726
|
+
validate(decoded);
|
|
1727
|
+
return decoded;
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
// src/api/Schema/requests.ts
|
|
1731
|
+
var MAX_LIMIT = 100;
|
|
1732
|
+
var DEFAULT_LIMIT = 20;
|
|
1733
|
+
var PaginationQueryParams = z6.object({
|
|
1734
|
+
cursor: z6.string().optional().refine(
|
|
1735
|
+
(val) => {
|
|
1736
|
+
if (!val) return true;
|
|
1737
|
+
try {
|
|
1738
|
+
const decoded = Cursor_exports.decode(val);
|
|
1739
|
+
return decoded !== null;
|
|
1740
|
+
} catch (_error) {
|
|
1741
|
+
return false;
|
|
1742
|
+
}
|
|
1743
|
+
},
|
|
1744
|
+
{
|
|
1745
|
+
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
1746
|
+
}
|
|
1747
|
+
).meta({
|
|
1748
|
+
description: "Pagination cursor in base64url-encoded format",
|
|
1749
|
+
example: "eyJzb3J0IjoicHJpY2UiLCJkaXIiOiJkZXNjIiwicHJpY2UiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwiaGFzaCI6IjB4ZGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIifQ"
|
|
1750
|
+
}),
|
|
1751
|
+
limit: z6.string().regex(/^[1-9]\d*$/, {
|
|
1752
|
+
message: "Limit must be a positive integer"
|
|
1753
|
+
}).transform((val) => Number.parseInt(val, 10)).pipe(
|
|
1754
|
+
z6.number().max(MAX_LIMIT, {
|
|
1755
|
+
message: `Limit cannot exceed ${MAX_LIMIT}`
|
|
1756
|
+
})
|
|
1757
|
+
).optional().default(DEFAULT_LIMIT).meta({
|
|
1758
|
+
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
|
|
1759
|
+
example: 10
|
|
1760
|
+
})
|
|
1761
|
+
});
|
|
1762
|
+
var GetOffersQueryParams = z6.object({
|
|
1763
|
+
...PaginationQueryParams.shape,
|
|
1764
|
+
side: z6.enum(["buy", "sell"]).meta({
|
|
1765
|
+
description: "Side of the offer.",
|
|
1766
|
+
example: "buy"
|
|
1767
|
+
}),
|
|
1768
|
+
obligation_id: z6.string({ error: "Obligation id is required and must be a valid 32-byte hex string" }).regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).meta({
|
|
1769
|
+
description: "Offers obligation id",
|
|
1770
|
+
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
1771
|
+
})
|
|
1772
|
+
});
|
|
1773
|
+
var GetObligationsQueryParams = z6.object({
|
|
1774
|
+
...PaginationQueryParams.shape,
|
|
1775
|
+
cursor: z6.string().optional().meta({
|
|
1776
|
+
description: "Obligation id cursor",
|
|
1777
|
+
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
1778
|
+
})
|
|
1779
|
+
});
|
|
1780
|
+
var schemas = {
|
|
1781
|
+
get_offers: GetOffersQueryParams,
|
|
1782
|
+
get_obligations: GetObligationsQueryParams
|
|
1783
|
+
};
|
|
1784
|
+
function parse(action, query) {
|
|
1785
|
+
return schemas[action].parse(query);
|
|
1786
|
+
}
|
|
1787
|
+
function safeParse(action, query, error2) {
|
|
1788
|
+
return schemas[action].safeParse(query, {
|
|
1789
|
+
error: error2
|
|
1790
|
+
});
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
// src/api/Schema/openapi.ts
|
|
1794
|
+
var timestampExample = "2024-01-01T12:00:00.000Z";
|
|
1795
|
+
var cursorExample = "eyJvZmZzZXQiOjEwMH0";
|
|
1796
|
+
function makeSuccessResponse(parameters) {
|
|
1797
|
+
const { dataSchema, dataDescription, dataExample, cursor } = parameters;
|
|
1798
|
+
const withDataMeta = dataDescription ? dataSchema.meta({ description: dataDescription }) : dataSchema;
|
|
1799
|
+
return z.object({
|
|
1800
|
+
status: z.literal("success"),
|
|
1801
|
+
cursor: z.string().nullable(),
|
|
1802
|
+
data: z.any(),
|
|
1803
|
+
meta: z.object({
|
|
1804
|
+
timestamp: z.string()
|
|
1805
|
+
})
|
|
1806
|
+
}).extend({
|
|
1807
|
+
data: withDataMeta
|
|
1808
|
+
}).meta({
|
|
1809
|
+
example: {
|
|
1810
|
+
status: "success",
|
|
1811
|
+
cursor,
|
|
1812
|
+
data: dataExample,
|
|
1813
|
+
meta: { timestamp: timestampExample }
|
|
1814
|
+
}
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
var OffersSuccessResponseSchema = makeSuccessResponse({
|
|
1818
|
+
dataSchema: z.array(z.any()),
|
|
1819
|
+
dataDescription: "Offers matching the provided filters.",
|
|
1820
|
+
dataExample: [toSnakeCase(Offer_exports.random())],
|
|
1821
|
+
cursor: cursorExample
|
|
1822
|
+
});
|
|
1823
|
+
var ObligationsSuccessResponseSchema = makeSuccessResponse({
|
|
1824
|
+
dataSchema: z.array(z.any()),
|
|
1825
|
+
dataDescription: "Obligations known to the router.",
|
|
1826
|
+
dataExample: [toSnakeCase(Obligation_exports.random())],
|
|
1827
|
+
cursor: cursorExample
|
|
1828
|
+
});
|
|
1829
|
+
var RouterStatusSuccessResponseSchema = makeSuccessResponse({
|
|
1830
|
+
dataSchema: RouterStatusResponse,
|
|
1831
|
+
dataDescription: "Aggregated router status.",
|
|
1832
|
+
dataExample: { status: "live" },
|
|
1833
|
+
cursor: null
|
|
1834
|
+
});
|
|
1835
|
+
var CollectorsHealthSuccessResponseSchema = makeSuccessResponse({
|
|
1836
|
+
dataSchema: CollectorsHealthResponse,
|
|
1837
|
+
dataDescription: "Collectors health details and sync status.",
|
|
1838
|
+
dataExample: [
|
|
1839
|
+
{
|
|
1840
|
+
name: "mempool_offers",
|
|
1841
|
+
chain_id: "1",
|
|
1842
|
+
block_number: 21345678,
|
|
1843
|
+
updated_at: "2024-01-01T12:00:00.000Z",
|
|
1844
|
+
lag: 0,
|
|
1845
|
+
status: "live"
|
|
1846
|
+
}
|
|
1847
|
+
],
|
|
1848
|
+
cursor: null
|
|
1849
|
+
});
|
|
1850
|
+
var ChainsHealthSuccessResponseSchema = makeSuccessResponse({
|
|
1851
|
+
dataSchema: ChainsHealthResponse,
|
|
1852
|
+
dataDescription: "Latest processed block per chain.",
|
|
1853
|
+
dataExample: [
|
|
1854
|
+
{
|
|
1855
|
+
chain_id: "1",
|
|
1856
|
+
block_number: 21345678,
|
|
1857
|
+
updated_at: "2024-01-01T12:00:00.000Z"
|
|
1858
|
+
}
|
|
1859
|
+
],
|
|
1860
|
+
cursor: null
|
|
1861
|
+
});
|
|
1862
|
+
var errorResponseSchema = z.object({
|
|
1863
|
+
status: z.literal("error"),
|
|
1864
|
+
error: z.object({
|
|
1865
|
+
code: z.string(),
|
|
1866
|
+
message: z.string(),
|
|
1867
|
+
details: z.any().optional()
|
|
1868
|
+
}),
|
|
1869
|
+
meta: z.object({
|
|
1870
|
+
timestamp: z.string()
|
|
1871
|
+
})
|
|
1872
|
+
}).meta({
|
|
1873
|
+
description: "Error response wrapper.",
|
|
1874
|
+
example: {
|
|
1875
|
+
status: "error",
|
|
1876
|
+
error: {
|
|
1877
|
+
code: "VALIDATION_ERROR",
|
|
1878
|
+
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object",
|
|
1879
|
+
details: [
|
|
1880
|
+
{
|
|
1881
|
+
field: "cursor",
|
|
1882
|
+
issue: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
1883
|
+
}
|
|
1884
|
+
]
|
|
1885
|
+
},
|
|
1886
|
+
meta: {
|
|
1887
|
+
timestamp: timestampExample
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
});
|
|
1891
|
+
var paths = {
|
|
1892
|
+
"/v1/offers": {
|
|
1893
|
+
get: {
|
|
1894
|
+
summary: "Offers",
|
|
1895
|
+
description: "Find offers that match specific criteria",
|
|
1896
|
+
tags: ["Offers"],
|
|
1897
|
+
requestParams: {
|
|
1898
|
+
query: GetOffersQueryParams
|
|
1899
|
+
},
|
|
1900
|
+
responses: {
|
|
1901
|
+
200: {
|
|
1902
|
+
description: "Success",
|
|
1903
|
+
content: {
|
|
1904
|
+
"application/json": {
|
|
1905
|
+
schema: OffersSuccessResponseSchema
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
},
|
|
1909
|
+
400: {
|
|
1910
|
+
description: "Bad Request",
|
|
1911
|
+
content: {
|
|
1912
|
+
"application/json": {
|
|
1913
|
+
schema: errorResponseSchema
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
},
|
|
1920
|
+
"/v1/obligations": {
|
|
1921
|
+
get: {
|
|
1922
|
+
summary: "Obligations",
|
|
1923
|
+
description: "List obligations with pagination support",
|
|
1924
|
+
tags: ["Obligations"],
|
|
1925
|
+
requestParams: {
|
|
1926
|
+
query: GetObligationsQueryParams
|
|
1927
|
+
},
|
|
1928
|
+
responses: {
|
|
1929
|
+
200: {
|
|
1930
|
+
description: "Success",
|
|
1931
|
+
content: {
|
|
1932
|
+
"application/json": {
|
|
1933
|
+
schema: ObligationsSuccessResponseSchema
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
},
|
|
1937
|
+
400: {
|
|
1938
|
+
description: "Bad Request",
|
|
1939
|
+
content: {
|
|
1940
|
+
"application/json": {
|
|
1941
|
+
schema: errorResponseSchema
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
},
|
|
1948
|
+
"/v1/health": {
|
|
1949
|
+
get: {
|
|
1950
|
+
summary: "Router status",
|
|
1951
|
+
description: "Retrieve the aggregated status of the router.",
|
|
1952
|
+
tags: ["Health"],
|
|
1953
|
+
responses: {
|
|
1954
|
+
200: {
|
|
1955
|
+
description: "Success",
|
|
1956
|
+
content: {
|
|
1957
|
+
"application/json": {
|
|
1958
|
+
schema: RouterStatusSuccessResponseSchema
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
},
|
|
1965
|
+
"/v1/health/collectors": {
|
|
1966
|
+
get: {
|
|
1967
|
+
summary: "Collectors health",
|
|
1968
|
+
description: "Retrieve the block numbers processed by collectors and their sync status.",
|
|
1969
|
+
tags: ["Health"],
|
|
1970
|
+
responses: {
|
|
1971
|
+
200: {
|
|
1972
|
+
description: "Success",
|
|
1973
|
+
content: {
|
|
1974
|
+
"application/json": {
|
|
1975
|
+
schema: CollectorsHealthSuccessResponseSchema
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
},
|
|
1982
|
+
"/v1/health/chains": {
|
|
1983
|
+
get: {
|
|
1984
|
+
summary: "Chains health",
|
|
1985
|
+
description: "Retrieve the latest block processed for each chain.",
|
|
1986
|
+
tags: ["Health"],
|
|
1987
|
+
responses: {
|
|
1988
|
+
200: {
|
|
1989
|
+
description: "Success",
|
|
1990
|
+
content: {
|
|
1991
|
+
"application/json": {
|
|
1992
|
+
schema: ChainsHealthSuccessResponseSchema
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
};
|
|
2000
|
+
var OpenApi = createDocument({
|
|
2001
|
+
openapi: "3.1.0",
|
|
2002
|
+
info: {
|
|
2003
|
+
title: "Router API",
|
|
2004
|
+
version: "1.0.0",
|
|
2005
|
+
description: "API for the Morpho Router"
|
|
2006
|
+
},
|
|
2007
|
+
tags: [
|
|
2008
|
+
{
|
|
2009
|
+
name: "Offers"
|
|
2010
|
+
},
|
|
2011
|
+
{
|
|
2012
|
+
name: "Obligations"
|
|
2013
|
+
},
|
|
2014
|
+
{
|
|
2015
|
+
name: "Health"
|
|
2016
|
+
}
|
|
2017
|
+
],
|
|
2018
|
+
servers: [
|
|
2019
|
+
{
|
|
2020
|
+
url: "https://router.morpho.dev",
|
|
2021
|
+
description: "Production server"
|
|
2022
|
+
},
|
|
2023
|
+
{
|
|
2024
|
+
url: "http://localhost:7891",
|
|
2025
|
+
description: "Local development server"
|
|
2026
|
+
}
|
|
2027
|
+
],
|
|
2028
|
+
paths
|
|
2029
|
+
});
|
|
2030
|
+
|
|
2031
|
+
// src/api/Controllers/getDocs.ts
|
|
2032
|
+
function getSwaggerJson() {
|
|
2033
|
+
return OpenApi;
|
|
2034
|
+
}
|
|
2035
|
+
function getDocsHtml() {
|
|
2036
|
+
const html = `<!DOCTYPE html>
|
|
2037
|
+
<html>
|
|
2038
|
+
<head>
|
|
2039
|
+
<meta charset="UTF-8">
|
|
2040
|
+
<title>Router API Docs (Scalar)</title>
|
|
2041
|
+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
2042
|
+
<style>
|
|
2043
|
+
html, body { margin: 0; height: 100%; }
|
|
2044
|
+
api-reference { height: 100%; width: 100%; }
|
|
2045
|
+
</style>
|
|
2046
|
+
</head>
|
|
2047
|
+
<body>
|
|
2048
|
+
<div id="api-container" style="height:100%;width:100%;"></div>
|
|
2049
|
+
<script>
|
|
2050
|
+
window.addEventListener('load', function () {
|
|
2051
|
+
const spec = ${JSON.stringify(OpenApi)};
|
|
2052
|
+
Scalar.createApiReference('#api-container', { spec: { content: spec } });
|
|
2053
|
+
});
|
|
2054
|
+
</script>
|
|
2055
|
+
</body>
|
|
2056
|
+
</html>`;
|
|
2057
|
+
return html;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
// src/services/Health.ts
|
|
2061
|
+
var Health_exports = {};
|
|
2062
|
+
__export(Health_exports, {
|
|
2063
|
+
create: () => create9
|
|
2064
|
+
});
|
|
2065
|
+
|
|
2066
|
+
// src/collectors/index.ts
|
|
2067
|
+
var collectors_exports = {};
|
|
2068
|
+
__export(collectors_exports, {
|
|
2069
|
+
batch: () => batch2,
|
|
2070
|
+
create: () => create2,
|
|
2071
|
+
createBuilder: () => createBuilder,
|
|
2072
|
+
fetchBalancesAndAllowances: () => fetchBalancesAndAllowances,
|
|
2073
|
+
fetchCollateralAndDebt: () => fetchCollateralAndDebt,
|
|
2074
|
+
fetchOraclePrices: () => fetchOraclePrices,
|
|
2075
|
+
fetchUserVaultMarketLiquidity: () => fetchUserVaultMarketLiquidity,
|
|
2076
|
+
morpho: () => morpho,
|
|
2077
|
+
names: () => names,
|
|
2078
|
+
run: () => run,
|
|
2079
|
+
single: () => single,
|
|
2080
|
+
start: () => start
|
|
2081
|
+
});
|
|
2082
|
+
|
|
2083
|
+
// src/services/Logger.ts
|
|
2084
|
+
var Logger_exports = {};
|
|
2085
|
+
__export(Logger_exports, {
|
|
2086
|
+
LogLevelValues: () => LogLevelValues,
|
|
2087
|
+
defaultLogger: () => defaultLogger,
|
|
2088
|
+
getLogger: () => getLogger,
|
|
2089
|
+
runWithLogger: () => runWithLogger,
|
|
2090
|
+
silentLogger: () => silentLogger
|
|
2091
|
+
});
|
|
2092
|
+
var LogLevelValues = [
|
|
2093
|
+
"trace",
|
|
2094
|
+
"debug",
|
|
2095
|
+
"info",
|
|
2096
|
+
"warn",
|
|
2097
|
+
"error",
|
|
2098
|
+
"fatal",
|
|
2099
|
+
"silent"
|
|
2100
|
+
];
|
|
2101
|
+
function defaultLogger(minLevel, pretty) {
|
|
2102
|
+
const threshold = minLevel ?? process.env.ROUTER_LOG_LEVEL ?? "info";
|
|
2103
|
+
const prettyEnabled = typeof pretty === "boolean" ? pretty : String(process.env.ROUTER_LOG_PRETTY ?? "false").toLowerCase() === "true";
|
|
2104
|
+
const levelIndexByName = LogLevelValues.reduce(
|
|
2105
|
+
(acc, lvl, idx) => {
|
|
2106
|
+
acc[lvl] = idx;
|
|
2107
|
+
return acc;
|
|
2108
|
+
},
|
|
2109
|
+
{}
|
|
2110
|
+
);
|
|
2111
|
+
const isEnabled = (methodLevel) => levelIndexByName[methodLevel] >= levelIndexByName[threshold];
|
|
2112
|
+
const wrap = (consoleMethod, methodLevel) => isEnabled(methodLevel) ? (entry) => {
|
|
2113
|
+
if (!prettyEnabled) {
|
|
2114
|
+
console[consoleMethod](stringify({ level: methodLevel, ...entry }));
|
|
2115
|
+
return;
|
|
2116
|
+
}
|
|
2117
|
+
const { msg, ...rest } = entry;
|
|
2118
|
+
const stack = typeof rest.stack === "string" ? rest.stack : void 0;
|
|
2119
|
+
if (stack) delete rest.stack;
|
|
2120
|
+
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
2121
|
+
const level = methodLevel.toUpperCase();
|
|
2122
|
+
const extras = Object.entries(rest).map(([k, v]) => `${k}=${formatValue(v)}`).join(" ");
|
|
2123
|
+
const line = extras.length > 0 ? `${timestamp2} [${level}] ${msg} ${extras}` : `${timestamp2} [${level}] ${msg}`;
|
|
2124
|
+
console[consoleMethod](line);
|
|
2125
|
+
if (stack) {
|
|
2126
|
+
console[consoleMethod](stack);
|
|
2127
|
+
}
|
|
2128
|
+
} : () => {
|
|
2129
|
+
};
|
|
2130
|
+
return {
|
|
2131
|
+
trace: wrap("trace", "trace"),
|
|
2132
|
+
debug: wrap("debug", "debug"),
|
|
2133
|
+
info: wrap("info", "info"),
|
|
2134
|
+
warn: wrap("warn", "warn"),
|
|
2135
|
+
error: wrap("error", "error"),
|
|
2136
|
+
fatal: wrap("error", "fatal")
|
|
2137
|
+
};
|
|
1843
2138
|
}
|
|
1844
|
-
function
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
offering: offer.offering.toLowerCase(),
|
|
1849
|
-
assets: offer.assets,
|
|
1850
|
-
rate: offer.rate,
|
|
1851
|
-
maturity: BigInt(offer.maturity),
|
|
1852
|
-
expiry: BigInt(offer.expiry),
|
|
1853
|
-
nonce: offer.nonce,
|
|
1854
|
-
buy: offer.buy,
|
|
1855
|
-
loanToken: offer.loanToken.toLowerCase(),
|
|
1856
|
-
collaterals: offer.collaterals,
|
|
1857
|
-
callback: {
|
|
1858
|
-
address: offer.callback.address.toLowerCase(),
|
|
1859
|
-
data: offer.callback.data,
|
|
1860
|
-
gasLimit: offer.callback.gasLimit
|
|
1861
|
-
}
|
|
1862
|
-
},
|
|
1863
|
-
primaryType: "Offer",
|
|
1864
|
-
types
|
|
1865
|
-
});
|
|
2139
|
+
function silentLogger() {
|
|
2140
|
+
const noop = () => {
|
|
2141
|
+
};
|
|
2142
|
+
return { trace: noop, debug: noop, info: noop, warn: noop, error: noop, fatal: noop };
|
|
1866
2143
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
chainId: offer.chainId,
|
|
1871
|
-
loanToken: offer.loanToken,
|
|
1872
|
-
collaterals: offer.collaterals,
|
|
1873
|
-
maturity: offer.maturity
|
|
1874
|
-
})
|
|
1875
|
-
);
|
|
2144
|
+
var loggerContext = new AsyncLocalStorage();
|
|
2145
|
+
function runWithLogger(logger, fn) {
|
|
2146
|
+
return loggerContext.run(logger, fn);
|
|
1876
2147
|
}
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
{ name: "assets", type: "uint256" },
|
|
1880
|
-
{ name: "rate", type: "uint256" },
|
|
1881
|
-
{ name: "maturity", type: "uint256" },
|
|
1882
|
-
{ name: "expiry", type: "uint256" },
|
|
1883
|
-
{ name: "nonce", type: "uint256" },
|
|
1884
|
-
{ name: "buy", type: "bool" },
|
|
1885
|
-
{ name: "chainId", type: "uint256" },
|
|
1886
|
-
{ name: "loanToken", type: "address" },
|
|
1887
|
-
{ name: "start", type: "uint256" },
|
|
1888
|
-
{
|
|
1889
|
-
name: "collaterals",
|
|
1890
|
-
type: "tuple[]",
|
|
1891
|
-
components: [
|
|
1892
|
-
{ name: "asset", type: "address" },
|
|
1893
|
-
{ name: "oracle", type: "address" },
|
|
1894
|
-
{ name: "lltv", type: "uint256" }
|
|
1895
|
-
]
|
|
1896
|
-
},
|
|
1897
|
-
{
|
|
1898
|
-
name: "callback",
|
|
1899
|
-
type: "tuple",
|
|
1900
|
-
components: [
|
|
1901
|
-
{ name: "address", type: "address" },
|
|
1902
|
-
{ name: "data", type: "bytes" },
|
|
1903
|
-
{ name: "gasLimit", type: "uint256" }
|
|
1904
|
-
]
|
|
1905
|
-
},
|
|
1906
|
-
{ name: "signature", type: "bytes" }
|
|
1907
|
-
];
|
|
1908
|
-
function encode2(offer) {
|
|
1909
|
-
return encodeAbiParameters(OfferAbi, [
|
|
1910
|
-
offer.offering,
|
|
1911
|
-
offer.assets,
|
|
1912
|
-
offer.rate,
|
|
1913
|
-
BigInt(offer.maturity),
|
|
1914
|
-
BigInt(offer.expiry),
|
|
1915
|
-
offer.nonce,
|
|
1916
|
-
offer.buy,
|
|
1917
|
-
offer.chainId,
|
|
1918
|
-
offer.loanToken,
|
|
1919
|
-
BigInt(offer.start),
|
|
1920
|
-
offer.collaterals,
|
|
1921
|
-
offer.callback,
|
|
1922
|
-
offer.signature ?? "0x"
|
|
1923
|
-
]);
|
|
2148
|
+
function getLogger() {
|
|
2149
|
+
return loggerContext.getStore() ?? defaultLogger();
|
|
1924
2150
|
}
|
|
1925
|
-
function
|
|
1926
|
-
|
|
2151
|
+
function formatValue(value) {
|
|
2152
|
+
if (value === null || value === void 0 || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
|
|
2153
|
+
return String(value);
|
|
2154
|
+
}
|
|
2155
|
+
if (typeof value === "string") {
|
|
2156
|
+
if (value.includes(" ")) return JSON.stringify(value);
|
|
2157
|
+
return value;
|
|
2158
|
+
}
|
|
1927
2159
|
try {
|
|
1928
|
-
|
|
1929
|
-
} catch
|
|
1930
|
-
|
|
2160
|
+
return stringify(value);
|
|
2161
|
+
} catch {
|
|
2162
|
+
try {
|
|
2163
|
+
return JSON.stringify(value);
|
|
2164
|
+
} catch {
|
|
2165
|
+
return String(value);
|
|
2166
|
+
}
|
|
1931
2167
|
}
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
// src/services/RouterAdmin.ts
|
|
2171
|
+
function create(parameters) {
|
|
2172
|
+
const collector = "admin";
|
|
2173
|
+
const {
|
|
2174
|
+
client,
|
|
2175
|
+
chain,
|
|
2176
|
+
withTransaction,
|
|
2177
|
+
options: { maxBatchSize = 25, maxBlockNumber } = {}
|
|
2178
|
+
} = parameters;
|
|
2179
|
+
const maxBlockNumberBI = maxBlockNumber !== void 0 ? BigInt(maxBlockNumber) : void 0;
|
|
2180
|
+
let finalizedBlock = null;
|
|
2181
|
+
let unfinalizedBlocks = [];
|
|
2182
|
+
const logger = getLogger();
|
|
2183
|
+
let isMaxBlockNumberReached = false;
|
|
2184
|
+
let tick = 0;
|
|
2185
|
+
return {
|
|
2186
|
+
syncBlock: async () => {
|
|
2187
|
+
if (isMaxBlockNumberReached) return;
|
|
2188
|
+
const head = await client.getBlock({
|
|
2189
|
+
blockTag: "latest",
|
|
2190
|
+
includeTransactions: false
|
|
2191
|
+
});
|
|
2192
|
+
await withTransaction(async ({ chainStore, collectorStore }) => {
|
|
2193
|
+
const { epoch, blockNumber: latestSavedBlockNumber } = await chainStore.getBlockNumber(
|
|
2194
|
+
chain.id
|
|
2195
|
+
);
|
|
2196
|
+
if (maxBlockNumberBI !== void 0 && head.number >= maxBlockNumberBI) {
|
|
2197
|
+
logger.info({
|
|
2198
|
+
msg: `Head is greater than max block number`,
|
|
2199
|
+
collector,
|
|
2200
|
+
chainId: chain.id,
|
|
2201
|
+
block_number: head.number,
|
|
2202
|
+
max_block_number: maxBlockNumber
|
|
2203
|
+
});
|
|
2204
|
+
isMaxBlockNumberReached = true;
|
|
2205
|
+
await chainStore.saveBlockNumber({
|
|
2206
|
+
chainId: chain.id,
|
|
2207
|
+
blockNumber: maxBlockNumber,
|
|
2208
|
+
epoch: epoch + 1n
|
|
2209
|
+
});
|
|
2210
|
+
await Promise.all(
|
|
2211
|
+
names.map(
|
|
2212
|
+
async (collectorName) => collectorStore.saveBlockNumber({
|
|
2213
|
+
collectorName,
|
|
2214
|
+
chainId: chain.id,
|
|
2215
|
+
blockNumber: maxBlockNumber,
|
|
2216
|
+
epoch: epoch + 1n
|
|
2217
|
+
})
|
|
2218
|
+
)
|
|
2219
|
+
);
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
finalizedBlock = await fetchFinalizedBlock({
|
|
2223
|
+
tick,
|
|
2224
|
+
client,
|
|
2225
|
+
chain,
|
|
2226
|
+
logger,
|
|
2227
|
+
collector,
|
|
2228
|
+
unfinalizedBlocks,
|
|
2229
|
+
previousFinalizedBlock: finalizedBlock
|
|
2230
|
+
});
|
|
2231
|
+
tick++;
|
|
2232
|
+
let {
|
|
2233
|
+
block: returnedBlock,
|
|
2234
|
+
didReorgHappened,
|
|
2235
|
+
unfinalizedBlocks: newUnfinalizedBlocks
|
|
2236
|
+
} = await reconcile({
|
|
2237
|
+
client,
|
|
2238
|
+
block: head,
|
|
2239
|
+
unfinalizedBlocks,
|
|
2240
|
+
finalizedBlock,
|
|
2241
|
+
logger,
|
|
2242
|
+
collector,
|
|
2243
|
+
chain,
|
|
2244
|
+
maxBatchSize
|
|
2245
|
+
});
|
|
2246
|
+
unfinalizedBlocks = newUnfinalizedBlocks;
|
|
2247
|
+
const blockNumber = Number(returnedBlock.number);
|
|
2248
|
+
didReorgHappened = didReorgHappened || blockNumber < latestSavedBlockNumber;
|
|
2249
|
+
await chainStore.saveBlockNumber({
|
|
2250
|
+
chainId: chain.id,
|
|
2251
|
+
blockNumber,
|
|
2252
|
+
epoch: didReorgHappened ? epoch + 1n : epoch
|
|
2253
|
+
});
|
|
2254
|
+
if (didReorgHappened) {
|
|
2255
|
+
await Promise.all(
|
|
2256
|
+
names.map(
|
|
2257
|
+
async (collectorName) => collectorStore.saveBlockNumber({
|
|
2258
|
+
collectorName,
|
|
2259
|
+
chainId: chain.id,
|
|
2260
|
+
blockNumber,
|
|
2261
|
+
epoch: epoch + 1n
|
|
2262
|
+
})
|
|
2263
|
+
)
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
1948
2266
|
});
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
|
-
address: decoded[11].address,
|
|
1952
|
-
data: decoded[11].data,
|
|
1953
|
-
gasLimit: decoded[11].gasLimit
|
|
1954
|
-
},
|
|
1955
|
-
consumed: 0n,
|
|
1956
|
-
blockNumber: Number(blockNumber),
|
|
1957
|
-
...decoded[12] === "0x" ? {} : { signature: decoded[12] }
|
|
1958
|
-
});
|
|
1959
|
-
return offer;
|
|
2267
|
+
}
|
|
2268
|
+
};
|
|
1960
2269
|
}
|
|
1961
|
-
var
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
{ name: "user", type: "address", indexed: true, internalType: "address" },
|
|
1966
|
-
{ name: "nonce", type: "uint256", indexed: true, internalType: "uint256" },
|
|
1967
|
-
{ name: "amount", type: "uint256", indexed: false, internalType: "uint256" }
|
|
1968
|
-
],
|
|
1969
|
-
anonymous: false
|
|
2270
|
+
var commonAncestor = (block, unfinalizedBlocks) => {
|
|
2271
|
+
const parent = unfinalizedBlocks.find((b) => b.hash === block.parentHash);
|
|
2272
|
+
if (parent) return parent;
|
|
2273
|
+
return null;
|
|
1970
2274
|
};
|
|
1971
|
-
|
|
1972
|
-
|
|
2275
|
+
var fetchFinalizedBlock = async (parameters) => {
|
|
2276
|
+
let { tick, client, chain, logger, collector, unfinalizedBlocks, previousFinalizedBlock } = parameters;
|
|
2277
|
+
let finalizedBlock = previousFinalizedBlock;
|
|
2278
|
+
if (tick % 20 === 0 || previousFinalizedBlock === null) {
|
|
2279
|
+
finalizedBlock = await client.getBlock({
|
|
2280
|
+
blockTag: "finalized",
|
|
2281
|
+
includeTransactions: false
|
|
2282
|
+
});
|
|
2283
|
+
if (finalizedBlock === null || finalizedBlock.number === null) {
|
|
2284
|
+
const msg = "Failed to get finalized block";
|
|
2285
|
+
logger.fatal({ collector, chainId: chain.id, msg });
|
|
2286
|
+
throw new Error(msg);
|
|
2287
|
+
}
|
|
2288
|
+
unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number >= finalizedBlock.number);
|
|
2289
|
+
}
|
|
2290
|
+
if (finalizedBlock.number === null || finalizedBlock.hash === null || finalizedBlock.parentHash === null) {
|
|
2291
|
+
const msg = "Failed to get finalized block";
|
|
2292
|
+
logger.fatal({ collector, chainId: chain.id, msg });
|
|
2293
|
+
throw new Error(msg);
|
|
2294
|
+
}
|
|
1973
2295
|
return {
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
nonce,
|
|
1978
|
-
amount,
|
|
1979
|
-
blockNumber: Number(blockNumber)
|
|
2296
|
+
hash: finalizedBlock.hash,
|
|
2297
|
+
number: finalizedBlock.number,
|
|
2298
|
+
parentHash: finalizedBlock.parentHash
|
|
1980
2299
|
};
|
|
1981
|
-
}
|
|
1982
|
-
var InvalidOfferError = class extends BaseError {
|
|
1983
|
-
name = "Offer.InvalidOfferError";
|
|
1984
|
-
constructor(error2) {
|
|
1985
|
-
super("Invalid offer.", { cause: error2 });
|
|
1986
|
-
}
|
|
1987
2300
|
};
|
|
1988
|
-
var
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
2301
|
+
var reconcile = async (parameters) => {
|
|
2302
|
+
let { client, block, unfinalizedBlocks, finalizedBlock, logger, collector, chain, maxBatchSize } = parameters;
|
|
2303
|
+
if (block.hash === null || block.number === null || block.parentHash === null)
|
|
2304
|
+
throw new Error("Failed to get block");
|
|
2305
|
+
const latestBlock = unfinalizedBlocks[unfinalizedBlocks.length - 1];
|
|
2306
|
+
if (latestBlock === void 0) {
|
|
2307
|
+
const newBlock2 = {
|
|
2308
|
+
hash: block.hash,
|
|
2309
|
+
number: block.number,
|
|
2310
|
+
parentHash: block.parentHash
|
|
2311
|
+
};
|
|
2312
|
+
unfinalizedBlocks.push(newBlock2);
|
|
2313
|
+
return { block: newBlock2, didReorgHappened: false, unfinalizedBlocks };
|
|
2314
|
+
}
|
|
2315
|
+
if (latestBlock.hash === block.hash)
|
|
2316
|
+
return { block: latestBlock, didReorgHappened: false, unfinalizedBlocks };
|
|
2317
|
+
if (latestBlock.number >= block.number) {
|
|
2318
|
+
const ancestor = commonAncestor(block, unfinalizedBlocks) || finalizedBlock;
|
|
2319
|
+
logger.info({
|
|
2320
|
+
msg: `Reorg detected`,
|
|
2321
|
+
collector,
|
|
2322
|
+
chain_id: chain.id,
|
|
2323
|
+
ancestor: ancestor.number,
|
|
2324
|
+
block_range: [latestBlock.number, block.number]
|
|
2325
|
+
});
|
|
2326
|
+
unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number <= ancestor.number);
|
|
2327
|
+
return { block: ancestor, didReorgHappened: true, unfinalizedBlocks };
|
|
2328
|
+
}
|
|
2329
|
+
if (latestBlock.number + 1n < block.number) {
|
|
2330
|
+
logger.debug({
|
|
2331
|
+
collector,
|
|
2332
|
+
chain_id: chain.id,
|
|
2333
|
+
block_range: [latestBlock.number, block.number],
|
|
2334
|
+
msg: `Missing blocks`
|
|
2335
|
+
});
|
|
2336
|
+
const missingBlockNumbers = (() => {
|
|
2337
|
+
const missingBlockNumbers2 = [];
|
|
2338
|
+
let start2 = latestBlock.number + 1n;
|
|
2339
|
+
const threshold = latestBlock.number + BigInt(maxBatchSize) > block.number ? block.number : latestBlock.number + BigInt(maxBatchSize);
|
|
2340
|
+
while (start2 < threshold) {
|
|
2341
|
+
missingBlockNumbers2.push(start2);
|
|
2342
|
+
start2 = start2 + 1n;
|
|
2343
|
+
}
|
|
2344
|
+
return missingBlockNumbers2;
|
|
2345
|
+
})();
|
|
2346
|
+
const missingBlocks = await Promise.all(
|
|
2347
|
+
missingBlockNumbers.map(
|
|
2348
|
+
(blockNumber) => retry(async () => await client.getBlock({ blockNumber, includeTransactions: false }))
|
|
2349
|
+
)
|
|
2350
|
+
);
|
|
2351
|
+
for (const missingBlock of missingBlocks) {
|
|
2352
|
+
const { block: returnedBlock, didReorgHappened } = await reconcile({
|
|
2353
|
+
client,
|
|
2354
|
+
block: missingBlock,
|
|
2355
|
+
unfinalizedBlocks,
|
|
2356
|
+
finalizedBlock,
|
|
2357
|
+
logger,
|
|
2358
|
+
collector,
|
|
2359
|
+
chain,
|
|
2360
|
+
maxBatchSize
|
|
2361
|
+
});
|
|
2362
|
+
if (returnedBlock.number !== missingBlock.number)
|
|
2363
|
+
return { block: returnedBlock, didReorgHappened, unfinalizedBlocks };
|
|
2364
|
+
}
|
|
2365
|
+
return reconcile({
|
|
2366
|
+
client,
|
|
2367
|
+
block,
|
|
2368
|
+
unfinalizedBlocks,
|
|
2369
|
+
finalizedBlock,
|
|
2370
|
+
logger,
|
|
2371
|
+
collector,
|
|
2372
|
+
chain,
|
|
2373
|
+
maxBatchSize
|
|
2374
|
+
});
|
|
2375
|
+
}
|
|
2376
|
+
if (block.parentHash !== latestBlock.hash) {
|
|
2377
|
+
const ancestor = commonAncestor(block, unfinalizedBlocks) || finalizedBlock;
|
|
2378
|
+
logger.info({
|
|
2379
|
+
msg: `Reorg detected`,
|
|
2380
|
+
collector,
|
|
2381
|
+
chain_id: chain.id,
|
|
2382
|
+
ancestor: ancestor.number,
|
|
2383
|
+
block_range: [latestBlock.number, block.number]
|
|
2384
|
+
});
|
|
2385
|
+
unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number <= ancestor.number);
|
|
2386
|
+
return { block: ancestor, didReorgHappened: true, unfinalizedBlocks };
|
|
1992
2387
|
}
|
|
2388
|
+
const newBlock = {
|
|
2389
|
+
hash: block.hash,
|
|
2390
|
+
number: block.number,
|
|
2391
|
+
parentHash: block.parentHash
|
|
2392
|
+
};
|
|
2393
|
+
unfinalizedBlocks.push(newBlock);
|
|
2394
|
+
return { block: newBlock, didReorgHappened: false, unfinalizedBlocks };
|
|
1993
2395
|
};
|
|
1994
2396
|
|
|
1995
|
-
// src/
|
|
1996
|
-
var
|
|
2397
|
+
// src/collectors/Collector.ts
|
|
2398
|
+
var names = [
|
|
2399
|
+
"mempool_offers",
|
|
2400
|
+
"consumed_events",
|
|
2401
|
+
"buy_with_empty_callback_liquidity",
|
|
2402
|
+
"buy_vault_v1_callback_liquidity",
|
|
2403
|
+
"sell_erc20_callback_liquidity"
|
|
2404
|
+
];
|
|
2405
|
+
function create2({
|
|
2406
|
+
name,
|
|
2407
|
+
collect,
|
|
2408
|
+
client,
|
|
2409
|
+
chain,
|
|
2410
|
+
withTransaction,
|
|
2411
|
+
collectorStore,
|
|
2412
|
+
options
|
|
2413
|
+
}) {
|
|
2414
|
+
const admin = create({
|
|
2415
|
+
client,
|
|
2416
|
+
chain,
|
|
2417
|
+
withTransaction,
|
|
2418
|
+
options
|
|
2419
|
+
});
|
|
2420
|
+
return {
|
|
2421
|
+
name,
|
|
2422
|
+
chain,
|
|
2423
|
+
collect: lazy((emit) => {
|
|
2424
|
+
const collector = name;
|
|
2425
|
+
const logger = getLogger();
|
|
2426
|
+
logger.info({
|
|
2427
|
+
msg: `Collector started`,
|
|
2428
|
+
collector,
|
|
2429
|
+
chain_id: chain.id,
|
|
2430
|
+
interval: options.interval
|
|
2431
|
+
});
|
|
2432
|
+
return poll(
|
|
2433
|
+
async () => {
|
|
2434
|
+
try {
|
|
2435
|
+
let { blockNumber: lastBlockNumber, epoch } = await collectorStore.getBlockNumber({
|
|
2436
|
+
collectorName: name,
|
|
2437
|
+
chainId: chain.id
|
|
2438
|
+
});
|
|
2439
|
+
await admin.syncBlock();
|
|
2440
|
+
lastBlockNumber = await collect({
|
|
2441
|
+
chain,
|
|
2442
|
+
client,
|
|
2443
|
+
collector: name,
|
|
2444
|
+
epoch,
|
|
2445
|
+
lastBlockNumber,
|
|
2446
|
+
withTransaction
|
|
2447
|
+
});
|
|
2448
|
+
emit(lastBlockNumber);
|
|
2449
|
+
} catch (err) {
|
|
2450
|
+
const isError = err instanceof Error;
|
|
2451
|
+
logger.error({
|
|
2452
|
+
msg: "Collector error",
|
|
2453
|
+
collector,
|
|
2454
|
+
chain_id: chain.id,
|
|
2455
|
+
error: isError ? err.message : String(err),
|
|
2456
|
+
stack: isError ? err.stack : void 0
|
|
2457
|
+
});
|
|
2458
|
+
}
|
|
2459
|
+
},
|
|
2460
|
+
{ interval: options.interval }
|
|
2461
|
+
);
|
|
2462
|
+
})
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
function start(collector) {
|
|
2466
|
+
let stopped = false;
|
|
2467
|
+
const it = collector.collect();
|
|
2468
|
+
(async () => {
|
|
2469
|
+
while (!stopped) await it.next();
|
|
2470
|
+
await it.return();
|
|
2471
|
+
})();
|
|
2472
|
+
return () => {
|
|
2473
|
+
stopped = true;
|
|
2474
|
+
};
|
|
2475
|
+
}
|
|
1997
2476
|
|
|
1998
|
-
// src/mempool/
|
|
2477
|
+
// src/mempool/index.ts
|
|
2478
|
+
var mempool_exports = {};
|
|
2479
|
+
__export(mempool_exports, {
|
|
2480
|
+
ChainIdMismatchError: () => ChainIdMismatchError,
|
|
2481
|
+
ViemClientError: () => ViemClientError,
|
|
2482
|
+
WalletAccountNotSetError: () => WalletAccountNotSetError,
|
|
2483
|
+
add: () => add,
|
|
2484
|
+
connect: () => connect,
|
|
2485
|
+
from: () => from7,
|
|
2486
|
+
get: () => get,
|
|
2487
|
+
watch: () => watch
|
|
2488
|
+
});
|
|
1999
2489
|
var DEFAULT_BATCH_SIZE2 = 100;
|
|
2000
2490
|
var DEFAULT_BLOCK_WINDOW2 = 100;
|
|
2001
|
-
function
|
|
2491
|
+
function from7(parameters) {
|
|
2002
2492
|
const config = {
|
|
2003
2493
|
client: parameters.client,
|
|
2004
2494
|
mempoolAddress: parameters.mempoolAddress,
|
|
@@ -2140,7 +2630,7 @@ var ChainIdMismatchError = class extends BaseError {
|
|
|
2140
2630
|
|
|
2141
2631
|
// src/mempool/MempoolClient.ts
|
|
2142
2632
|
function connect(parameters) {
|
|
2143
|
-
return
|
|
2633
|
+
return from7(parameters);
|
|
2144
2634
|
}
|
|
2145
2635
|
|
|
2146
2636
|
// src/services/Services.ts
|
|
@@ -2148,7 +2638,7 @@ var Services_exports = {};
|
|
|
2148
2638
|
__export(Services_exports, {
|
|
2149
2639
|
createStores: () => createStores,
|
|
2150
2640
|
createWithTransaction: () => createWithTransaction,
|
|
2151
|
-
from: () =>
|
|
2641
|
+
from: () => from8
|
|
2152
2642
|
});
|
|
2153
2643
|
|
|
2154
2644
|
// src/indexer/RouterIndexer.ts
|
|
@@ -3055,9 +3545,67 @@ function create7(config) {
|
|
|
3055
3545
|
})
|
|
3056
3546
|
);
|
|
3057
3547
|
}
|
|
3058
|
-
const returnedItems = Array.from(items.values());
|
|
3059
|
-
const nextCursor = returnedItems.length === limit && returnedItems.length > 0 ? result[result.length - 1].obligationId : null;
|
|
3060
|
-
return { obligations: returnedItems, nextCursor };
|
|
3548
|
+
const returnedItems = Array.from(items.values());
|
|
3549
|
+
const nextCursor = returnedItems.length === limit && returnedItems.length > 0 ? result[result.length - 1].obligationId : null;
|
|
3550
|
+
return { obligations: returnedItems, nextCursor };
|
|
3551
|
+
},
|
|
3552
|
+
getQuotes: async (parameters) => {
|
|
3553
|
+
const { obligationIds } = parameters;
|
|
3554
|
+
if (obligationIds.length === 0) return [];
|
|
3555
|
+
const now2 = time_exports.now();
|
|
3556
|
+
const sumConsumed = db.select({
|
|
3557
|
+
consumed: sql`COALESCE(SUM(${consumed.consumed}), 0)`.as("consumed")
|
|
3558
|
+
}).from(consumed).where(
|
|
3559
|
+
and(
|
|
3560
|
+
eq(consumed.offering, offers.offering),
|
|
3561
|
+
eq(consumed.nonce, offers.nonce),
|
|
3562
|
+
eq(consumed.chainId, offers.chainId)
|
|
3563
|
+
)
|
|
3564
|
+
).as("sum_consumed");
|
|
3565
|
+
const remaining = sql`(${offers.assets} - COALESCE(${sumConsumed.consumed}, 0))`;
|
|
3566
|
+
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
3567
|
+
obligationId: offers.obligationId,
|
|
3568
|
+
rate: offers.rate
|
|
3569
|
+
}).from(offers).leftJoinLateral(sumConsumed, sql`true`).where(
|
|
3570
|
+
and(
|
|
3571
|
+
inArray(offers.obligationId, obligationIds),
|
|
3572
|
+
gte(offers.expiry, now2),
|
|
3573
|
+
gte(offers.maturity, now2),
|
|
3574
|
+
eq(offers.buy, side === "buy"),
|
|
3575
|
+
sql`${remaining} > 0`
|
|
3576
|
+
)
|
|
3577
|
+
).orderBy(
|
|
3578
|
+
offers.obligationId,
|
|
3579
|
+
// lower rates first for buy, higher rates first for sell
|
|
3580
|
+
side === "buy" ? asc(offers.rate) : desc(offers.rate)
|
|
3581
|
+
);
|
|
3582
|
+
const [bestBuys, bestSells] = await Promise.all([
|
|
3583
|
+
query({ side: "buy" }),
|
|
3584
|
+
query({ side: "sell" })
|
|
3585
|
+
]);
|
|
3586
|
+
const quotes = /* @__PURE__ */ new Map();
|
|
3587
|
+
for (const row of bestSells) {
|
|
3588
|
+
quotes.set(row.obligationId, {
|
|
3589
|
+
ask: { rate: row.rate },
|
|
3590
|
+
bid: { rate: 0n }
|
|
3591
|
+
});
|
|
3592
|
+
}
|
|
3593
|
+
for (const row of bestBuys) {
|
|
3594
|
+
const quote = quotes.get(row.obligationId);
|
|
3595
|
+
if (!quote) {
|
|
3596
|
+
quotes.set(row.obligationId, {
|
|
3597
|
+
ask: { rate: 0n },
|
|
3598
|
+
bid: { rate: row.rate }
|
|
3599
|
+
});
|
|
3600
|
+
continue;
|
|
3601
|
+
}
|
|
3602
|
+
quote.bid = { rate: row.rate };
|
|
3603
|
+
}
|
|
3604
|
+
return Array.from(quotes.entries()).map(([id2, quote]) => {
|
|
3605
|
+
return Quote_exports.from({ obligationId: id2, ask: quote.ask, bid: quote.bid });
|
|
3606
|
+
}).sort((a, b) => {
|
|
3607
|
+
return a.obligationId.localeCompare(b.obligationId);
|
|
3608
|
+
});
|
|
3061
3609
|
}
|
|
3062
3610
|
};
|
|
3063
3611
|
}
|
|
@@ -3785,7 +4333,7 @@ async function clean(pg) {
|
|
|
3785
4333
|
}
|
|
3786
4334
|
|
|
3787
4335
|
// src/services/Services.ts
|
|
3788
|
-
function
|
|
4336
|
+
function from8(config) {
|
|
3789
4337
|
const {
|
|
3790
4338
|
chain,
|
|
3791
4339
|
rpcUrl,
|
|
@@ -5437,7 +5985,7 @@ function handleZodError(error2) {
|
|
|
5437
5985
|
return new ValidationError("Validation failed", formattedErrors);
|
|
5438
5986
|
}
|
|
5439
5987
|
|
|
5440
|
-
// src/api/
|
|
5988
|
+
// src/api/Controllers/getHealth.ts
|
|
5441
5989
|
async function getHealth(healthService) {
|
|
5442
5990
|
const logger = Logger_exports.getLogger();
|
|
5443
5991
|
try {
|
|
@@ -5502,269 +6050,31 @@ async function getHealthCollectors(healthService) {
|
|
|
5502
6050
|
return error(err);
|
|
5503
6051
|
}
|
|
5504
6052
|
}
|
|
5505
|
-
var CollectorHealth = z.object({
|
|
5506
|
-
name: z.string(),
|
|
5507
|
-
chain_id: z.number(),
|
|
5508
|
-
block_number: z.number().nullable(),
|
|
5509
|
-
updated_at: z.string().nullable(),
|
|
5510
|
-
lag: z.number().nullable(),
|
|
5511
|
-
status: z.enum(["live", "lagging", "unknown"])
|
|
5512
|
-
});
|
|
5513
|
-
var CollectorsHealthResponse = z.object({
|
|
5514
|
-
collectors: z.array(CollectorHealth)
|
|
5515
|
-
});
|
|
5516
|
-
var ChainHealth = z.object({
|
|
5517
|
-
chain_id: z.number(),
|
|
5518
|
-
block_number: z.number(),
|
|
5519
|
-
updated_at: z.string()
|
|
5520
|
-
});
|
|
5521
|
-
var ChainsHealthResponse = z.object({
|
|
5522
|
-
chains: z.array(ChainHealth)
|
|
5523
|
-
});
|
|
5524
|
-
var RouterStatusResponse = z.object({
|
|
5525
|
-
status: z.enum(["live", "syncing"])
|
|
5526
|
-
});
|
|
5527
6053
|
|
|
5528
|
-
// src/api/
|
|
6054
|
+
// src/api/Schema/ObligationResponse.ts
|
|
5529
6055
|
var ObligationResponse_exports = {};
|
|
5530
6056
|
__export(ObligationResponse_exports, {
|
|
5531
|
-
from: () =>
|
|
6057
|
+
from: () => from9
|
|
5532
6058
|
});
|
|
5533
|
-
function
|
|
5534
|
-
return toSnakeCase({
|
|
6059
|
+
function from9(obligation, quote) {
|
|
6060
|
+
return toSnakeCase({
|
|
6061
|
+
id: quote.obligationId,
|
|
6062
|
+
...obligation,
|
|
6063
|
+
ask: quote.ask,
|
|
6064
|
+
bid: quote.bid
|
|
6065
|
+
});
|
|
5535
6066
|
}
|
|
5536
6067
|
|
|
5537
|
-
// src/api/
|
|
6068
|
+
// src/api/Schema/OfferResponse.ts
|
|
5538
6069
|
var OfferResponse_exports = {};
|
|
5539
6070
|
__export(OfferResponse_exports, {
|
|
5540
|
-
from: () =>
|
|
6071
|
+
from: () => from10
|
|
5541
6072
|
});
|
|
5542
|
-
function
|
|
6073
|
+
function from10(offer) {
|
|
5543
6074
|
return toSnakeCase(offer);
|
|
5544
6075
|
}
|
|
5545
|
-
var MAX_LIMIT = 100;
|
|
5546
|
-
var DEFAULT_LIMIT = 20;
|
|
5547
|
-
var PaginationQueryParams = z6.object({
|
|
5548
|
-
cursor: z6.string().optional().refine(
|
|
5549
|
-
(val) => {
|
|
5550
|
-
if (!val) return true;
|
|
5551
|
-
try {
|
|
5552
|
-
const decoded = Cursor_exports.decode(val);
|
|
5553
|
-
return decoded !== null;
|
|
5554
|
-
} catch (_error) {
|
|
5555
|
-
return false;
|
|
5556
|
-
}
|
|
5557
|
-
},
|
|
5558
|
-
{
|
|
5559
|
-
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
5560
|
-
}
|
|
5561
|
-
).meta({
|
|
5562
|
-
description: "Pagination cursor in base64url-encoded format",
|
|
5563
|
-
example: "eyJzb3J0IjoicHJpY2UiLCJkaXIiOiJkZXNjIiwicHJpY2UiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwiaGFzaCI6IjB4ZGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIifQ"
|
|
5564
|
-
}),
|
|
5565
|
-
limit: z6.string().regex(/^[1-9]\d*$/, {
|
|
5566
|
-
message: "Limit must be a positive integer"
|
|
5567
|
-
}).transform((val) => Number.parseInt(val, 10)).pipe(
|
|
5568
|
-
z6.number().max(MAX_LIMIT, {
|
|
5569
|
-
message: `Limit cannot exceed ${MAX_LIMIT}`
|
|
5570
|
-
})
|
|
5571
|
-
).optional().default(DEFAULT_LIMIT).meta({
|
|
5572
|
-
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
|
|
5573
|
-
example: 10
|
|
5574
|
-
})
|
|
5575
|
-
});
|
|
5576
|
-
var GetOffersQueryParams = z6.object({
|
|
5577
|
-
...PaginationQueryParams.shape,
|
|
5578
|
-
side: z6.enum(["buy", "sell"]).meta({
|
|
5579
|
-
description: "Side of the offer.",
|
|
5580
|
-
example: "buy"
|
|
5581
|
-
}),
|
|
5582
|
-
obligation_id: z6.string({ error: "Obligation id is required and must be a valid 32-byte hex string" }).regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).meta({
|
|
5583
|
-
description: "Offers obligation id",
|
|
5584
|
-
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
5585
|
-
})
|
|
5586
|
-
});
|
|
5587
|
-
var GetObligationsQueryParams = z6.object({
|
|
5588
|
-
...PaginationQueryParams.shape,
|
|
5589
|
-
cursor: z6.string().optional().meta({
|
|
5590
|
-
description: "Obligation id cursor",
|
|
5591
|
-
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
5592
|
-
})
|
|
5593
|
-
});
|
|
5594
|
-
var schemas = {
|
|
5595
|
-
get_offers: GetOffersQueryParams,
|
|
5596
|
-
get_obligations: GetObligationsQueryParams
|
|
5597
|
-
};
|
|
5598
|
-
function parse(action, query) {
|
|
5599
|
-
return schemas[action].parse(query);
|
|
5600
|
-
}
|
|
5601
|
-
function safeParse(action, query, error2) {
|
|
5602
|
-
return schemas[action].safeParse(query, {
|
|
5603
|
-
error: error2
|
|
5604
|
-
});
|
|
5605
|
-
}
|
|
5606
|
-
|
|
5607
|
-
// src/api/Api/Schema/openapi.ts
|
|
5608
|
-
var successResponseSchema = z.object({
|
|
5609
|
-
status: z.literal("success"),
|
|
5610
|
-
cursor: z.string().nullable(),
|
|
5611
|
-
data: z.array(z.any()),
|
|
5612
|
-
meta: z.object({
|
|
5613
|
-
timestamp: z.string()
|
|
5614
|
-
})
|
|
5615
|
-
});
|
|
5616
|
-
var errorResponseSchema = z.object({
|
|
5617
|
-
status: z.literal("error"),
|
|
5618
|
-
error: z.object({
|
|
5619
|
-
code: z.string(),
|
|
5620
|
-
message: z.string(),
|
|
5621
|
-
details: z.any().optional()
|
|
5622
|
-
}),
|
|
5623
|
-
meta: z.object({
|
|
5624
|
-
timestamp: z.string()
|
|
5625
|
-
})
|
|
5626
|
-
});
|
|
5627
|
-
var paths = {
|
|
5628
|
-
"/v1/offers": {
|
|
5629
|
-
get: {
|
|
5630
|
-
summary: "Offers",
|
|
5631
|
-
description: "Find offers that match specific criteria",
|
|
5632
|
-
tags: ["Offers"],
|
|
5633
|
-
requestParams: {
|
|
5634
|
-
query: GetOffersQueryParams
|
|
5635
|
-
},
|
|
5636
|
-
responses: {
|
|
5637
|
-
200: {
|
|
5638
|
-
description: "Success",
|
|
5639
|
-
content: {
|
|
5640
|
-
"application/json": {
|
|
5641
|
-
schema: successResponseSchema
|
|
5642
|
-
}
|
|
5643
|
-
}
|
|
5644
|
-
},
|
|
5645
|
-
400: {
|
|
5646
|
-
description: "Bad Request",
|
|
5647
|
-
content: {
|
|
5648
|
-
"application/json": {
|
|
5649
|
-
schema: errorResponseSchema
|
|
5650
|
-
}
|
|
5651
|
-
}
|
|
5652
|
-
}
|
|
5653
|
-
}
|
|
5654
|
-
}
|
|
5655
|
-
},
|
|
5656
|
-
"/v1/obligations": {
|
|
5657
|
-
get: {
|
|
5658
|
-
summary: "Obligations",
|
|
5659
|
-
description: "List obligations with pagination support",
|
|
5660
|
-
tags: ["Obligations"],
|
|
5661
|
-
requestParams: {
|
|
5662
|
-
query: GetObligationsQueryParams
|
|
5663
|
-
},
|
|
5664
|
-
responses: {
|
|
5665
|
-
200: {
|
|
5666
|
-
description: "Success",
|
|
5667
|
-
content: {
|
|
5668
|
-
"application/json": {
|
|
5669
|
-
schema: successResponseSchema
|
|
5670
|
-
}
|
|
5671
|
-
}
|
|
5672
|
-
},
|
|
5673
|
-
400: {
|
|
5674
|
-
description: "Bad Request",
|
|
5675
|
-
content: {
|
|
5676
|
-
"application/json": {
|
|
5677
|
-
schema: errorResponseSchema
|
|
5678
|
-
}
|
|
5679
|
-
}
|
|
5680
|
-
}
|
|
5681
|
-
}
|
|
5682
|
-
}
|
|
5683
|
-
},
|
|
5684
|
-
"/v1/health": {
|
|
5685
|
-
get: {
|
|
5686
|
-
summary: "Router status",
|
|
5687
|
-
description: "Retrieve the aggregated status of the router.",
|
|
5688
|
-
tags: ["Health"],
|
|
5689
|
-
responses: {
|
|
5690
|
-
200: {
|
|
5691
|
-
description: "Success",
|
|
5692
|
-
content: {
|
|
5693
|
-
"application/json": {
|
|
5694
|
-
schema: RouterStatusResponse
|
|
5695
|
-
}
|
|
5696
|
-
}
|
|
5697
|
-
}
|
|
5698
|
-
}
|
|
5699
|
-
}
|
|
5700
|
-
},
|
|
5701
|
-
"/v1/health/collectors": {
|
|
5702
|
-
get: {
|
|
5703
|
-
summary: "Collectors health",
|
|
5704
|
-
description: "Retrieve the block numbers processed by collectors and their sync status.",
|
|
5705
|
-
tags: ["Health"],
|
|
5706
|
-
responses: {
|
|
5707
|
-
200: {
|
|
5708
|
-
description: "Success",
|
|
5709
|
-
content: {
|
|
5710
|
-
"application/json": {
|
|
5711
|
-
schema: CollectorsHealthResponse
|
|
5712
|
-
}
|
|
5713
|
-
}
|
|
5714
|
-
}
|
|
5715
|
-
}
|
|
5716
|
-
}
|
|
5717
|
-
},
|
|
5718
|
-
"/v1/health/chains": {
|
|
5719
|
-
get: {
|
|
5720
|
-
summary: "Chains health",
|
|
5721
|
-
description: "Retrieve the latest block processed for each chain.",
|
|
5722
|
-
tags: ["Health"],
|
|
5723
|
-
responses: {
|
|
5724
|
-
200: {
|
|
5725
|
-
description: "Success",
|
|
5726
|
-
content: {
|
|
5727
|
-
"application/json": {
|
|
5728
|
-
schema: ChainsHealthResponse
|
|
5729
|
-
}
|
|
5730
|
-
}
|
|
5731
|
-
}
|
|
5732
|
-
}
|
|
5733
|
-
}
|
|
5734
|
-
}
|
|
5735
|
-
};
|
|
5736
|
-
var OpenApi = createDocument({
|
|
5737
|
-
openapi: "3.1.0",
|
|
5738
|
-
info: {
|
|
5739
|
-
title: "Router API",
|
|
5740
|
-
version: "1.0.0",
|
|
5741
|
-
description: "API for the Morpho Router"
|
|
5742
|
-
},
|
|
5743
|
-
tags: [
|
|
5744
|
-
{
|
|
5745
|
-
name: "Offers"
|
|
5746
|
-
},
|
|
5747
|
-
{
|
|
5748
|
-
name: "Obligations"
|
|
5749
|
-
},
|
|
5750
|
-
{
|
|
5751
|
-
name: "Health"
|
|
5752
|
-
}
|
|
5753
|
-
],
|
|
5754
|
-
servers: [
|
|
5755
|
-
{
|
|
5756
|
-
url: "https://router.morpho.dev",
|
|
5757
|
-
description: "Production server"
|
|
5758
|
-
},
|
|
5759
|
-
{
|
|
5760
|
-
url: "http://localhost:8081",
|
|
5761
|
-
description: "Local development server"
|
|
5762
|
-
}
|
|
5763
|
-
],
|
|
5764
|
-
paths
|
|
5765
|
-
});
|
|
5766
6076
|
|
|
5767
|
-
// src/api/
|
|
6077
|
+
// src/api/Controllers/getObligations.ts
|
|
5768
6078
|
async function getObligations(queryParameters, store) {
|
|
5769
6079
|
const logger = Logger_exports.getLogger();
|
|
5770
6080
|
const result = safeParse("get_obligations", queryParameters, (issue) => issue.message);
|
|
@@ -5775,8 +6085,20 @@ async function getObligations(queryParameters, store) {
|
|
|
5775
6085
|
cursor: query.cursor,
|
|
5776
6086
|
limit: query.limit
|
|
5777
6087
|
});
|
|
6088
|
+
const quotes = await store.getQuotes({
|
|
6089
|
+
obligationIds: obligations2.map((o) => Obligation_exports.id(o))
|
|
6090
|
+
});
|
|
5778
6091
|
return success({
|
|
5779
|
-
data: obligations2.map(
|
|
6092
|
+
data: obligations2.map(
|
|
6093
|
+
(o) => ObligationResponse_exports.from(
|
|
6094
|
+
o,
|
|
6095
|
+
quotes.find((q) => q.obligationId === Obligation_exports.id(o)) ?? {
|
|
6096
|
+
obligationId: Obligation_exports.id(o),
|
|
6097
|
+
ask: { rate: 0n },
|
|
6098
|
+
bid: { rate: 0n }
|
|
6099
|
+
}
|
|
6100
|
+
)
|
|
6101
|
+
),
|
|
5780
6102
|
cursor: nextCursor ?? null
|
|
5781
6103
|
});
|
|
5782
6104
|
} catch (err) {
|
|
@@ -5790,7 +6112,7 @@ async function getObligations(queryParameters, store) {
|
|
|
5790
6112
|
}
|
|
5791
6113
|
}
|
|
5792
6114
|
|
|
5793
|
-
// src/api/
|
|
6115
|
+
// src/api/Controllers/getOffers.ts
|
|
5794
6116
|
async function getOffers(queryParameters, store) {
|
|
5795
6117
|
const logger = Logger_exports.getLogger();
|
|
5796
6118
|
const result = safeParse("get_offers", queryParameters, (issue) => issue.message);
|
|
@@ -5818,7 +6140,7 @@ async function getOffers(queryParameters, store) {
|
|
|
5818
6140
|
}
|
|
5819
6141
|
}
|
|
5820
6142
|
|
|
5821
|
-
// src/api/Api
|
|
6143
|
+
// src/api/Api.ts
|
|
5822
6144
|
function create8(config) {
|
|
5823
6145
|
return {
|
|
5824
6146
|
serve: ({ port }) => {
|
|
@@ -5850,13 +6172,20 @@ function serve(parameters) {
|
|
|
5850
6172
|
const { statusCode, body } = await getHealthChains(healthService);
|
|
5851
6173
|
return c.json(body, statusCode);
|
|
5852
6174
|
});
|
|
6175
|
+
app.get(
|
|
6176
|
+
"/docs/swagger.json",
|
|
6177
|
+
(c) => c.text(JSON.stringify(getSwaggerJson()), 200, {
|
|
6178
|
+
"Content-Type": "application/json; charset=utf-8"
|
|
6179
|
+
})
|
|
6180
|
+
);
|
|
6181
|
+
app.get("/docs", (c) => c.html(getDocsHtml(), 200));
|
|
5853
6182
|
serve$1({
|
|
5854
6183
|
fetch: app.fetch,
|
|
5855
6184
|
port: parameters.port
|
|
5856
6185
|
});
|
|
5857
6186
|
}
|
|
5858
6187
|
|
|
5859
|
-
// src/
|
|
6188
|
+
// src/client/Client.ts
|
|
5860
6189
|
var Client_exports = {};
|
|
5861
6190
|
__export(Client_exports, {
|
|
5862
6191
|
HttpForbiddenError: () => HttpForbiddenError,
|
|
@@ -5911,8 +6240,16 @@ async function getObligations2(config, parameters) {
|
|
|
5911
6240
|
if (parameters?.limit !== void 0) {
|
|
5912
6241
|
url.searchParams.set("limit", parameters.limit.toString());
|
|
5913
6242
|
}
|
|
5914
|
-
const { cursor: returnedCursor, data:
|
|
5915
|
-
const obligations2 =
|
|
6243
|
+
const { cursor: returnedCursor, data: items } = await getApi(config, url);
|
|
6244
|
+
const obligations2 = items.map((item) => {
|
|
6245
|
+
const obligation = Obligation_exports.fromSnakeCase(item);
|
|
6246
|
+
const { obligationId: _, ...returned } = {
|
|
6247
|
+
id: () => Obligation_exports.id(obligation),
|
|
6248
|
+
...obligation,
|
|
6249
|
+
...Quote_exports.fromSnakeCase({ obligation_id: item.id, ask: item.ask, bid: item.bid })
|
|
6250
|
+
};
|
|
6251
|
+
return returned;
|
|
6252
|
+
});
|
|
5916
6253
|
return {
|
|
5917
6254
|
cursor: returnedCursor,
|
|
5918
6255
|
obligations: obligations2
|
|
@@ -5999,6 +6336,6 @@ var HttpGetApiFailedError = class extends BaseError {
|
|
|
5999
6336
|
}
|
|
6000
6337
|
};
|
|
6001
6338
|
|
|
6002
|
-
export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainHealth, ChainStore_exports as ChainStore, ChainsHealthResponse, Collateral_exports as Collateral, collectors_exports as Collector, CollectorHealth, CollectorStore_exports as CollectorStore, CollectorsHealthResponse, Cursor_exports as Cursor, Errors_exports as Errors, Format_exports as Format, Health_exports as Health, LLTV_exports as LLTV, Liquidity_exports as Liquidity, LiquidityStore_exports as LiquidityStore, Logger_exports as Logger, Maturity_exports as Maturity, mempool_exports as Mempool, Obligation_exports as Obligation, ObligationResponse_exports as ObligationResponse, Offer_exports as Offer, OfferResponse_exports as OfferResponse, OfferStore_exports as OfferStore, schema_exports as OffersSchema, OpenApi, PG_exports as PG,
|
|
6339
|
+
export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainHealth, ChainStore_exports as ChainStore, ChainsHealthResponse, Collateral_exports as Collateral, collectors_exports as Collector, CollectorHealth, CollectorStore_exports as CollectorStore, CollectorsHealthResponse, Cursor_exports as Cursor, Errors_exports as Errors, Format_exports as Format, Health_exports as Health, LLTV_exports as LLTV, Liquidity_exports as Liquidity, LiquidityStore_exports as LiquidityStore, Logger_exports as Logger, Maturity_exports as Maturity, mempool_exports as Mempool, Obligation_exports as Obligation, ObligationResponse_exports as ObligationResponse, Offer_exports as Offer, OfferResponse_exports as OfferResponse, OfferStore_exports as OfferStore, schema_exports as OffersSchema, OpenApi, PG_exports as PG, Quote_exports as Quote, RouterApi_exports as RouterApi, Client_exports as RouterClient, RouterIndexer_exports as RouterIndexer, RouterStatusResponse, Services_exports as Services, time_exports as Time, utils_exports as Utils, Validation_exports as Validation, ValidationRule_exports as ValidationRule, parse, safeParse };
|
|
6003
6340
|
//# sourceMappingURL=index.node.mjs.map
|
|
6004
6341
|
//# sourceMappingURL=index.node.mjs.map
|