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