@morpho-dev/router 0.1.11 → 0.1.15
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 +97 -64
- package/dist/cli.js +6043 -0
- package/dist/cli.js.map +1 -0
- package/dist/drizzle/router_v1.4/0000_add_obligation_id.sql +112 -0
- package/dist/drizzle/router_v1.4/0001_update-primary-key-on-link.sql +3 -0
- package/dist/drizzle/{offers_v1.1/meta/0006_snapshot.json → router_v1.4/meta/0000_snapshot.json} +344 -256
- package/dist/drizzle/{offers_v1.1/meta/0007_snapshot.json → router_v1.4/meta/0001_snapshot.json} +306 -266
- package/dist/drizzle/router_v1.4/meta/_journal.json +20 -0
- package/dist/index.browser.d.cts +1367 -559
- package/dist/index.browser.d.ts +1367 -559
- package/dist/index.browser.js +1911 -835
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +1878 -830
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.cts +2827 -1562
- package/dist/index.node.d.ts +2827 -1562
- package/dist/index.node.js +5964 -2718
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +5915 -2710
- package/dist/index.node.mjs.map +1 -1
- package/package.json +16 -10
- package/dist/drizzle/offers_v1.1/0000_init.sql +0 -95
- package/dist/drizzle/offers_v1.1/0001_new_table_for_collectors_block_numbers.sql +0 -5
- package/dist/drizzle/offers_v1.1/0002_update-liquidity-tables.sql +0 -8
- package/dist/drizzle/offers_v1.1/0003_add-not-null-for-queue-id.sql +0 -1
- package/dist/drizzle/offers_v1.1/0004_add-callback-id-to-offer.sql +0 -1
- package/dist/drizzle/offers_v1.1/0005_add-missing-indices-to-liquidity-tables.sql +0 -2
- package/dist/drizzle/offers_v1.1/0006_add-callback-amount-to-queues-table.sql +0 -1
- package/dist/drizzle/offers_v1.1/0007_add-index-to-created-at.sql +0 -2
- package/dist/drizzle/offers_v1.1/meta/0000_snapshot.json +0 -827
- package/dist/drizzle/offers_v1.1/meta/0001_snapshot.json +0 -827
- package/dist/drizzle/offers_v1.1/meta/0002_snapshot.json +0 -833
- package/dist/drizzle/offers_v1.1/meta/0003_snapshot.json +0 -833
- package/dist/drizzle/offers_v1.1/meta/0004_snapshot.json +0 -839
- package/dist/drizzle/offers_v1.1/meta/0005_snapshot.json +0 -877
- package/dist/drizzle/offers_v1.1/meta/_journal.json +0 -62
package/dist/index.browser.js
CHANGED
|
@@ -1,133 +1,323 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var v4 = require('zod/v4');
|
|
4
4
|
var viem = require('viem');
|
|
5
|
+
var actions = require('viem/actions');
|
|
6
|
+
var chains$1 = require('viem/chains');
|
|
7
|
+
var z7 = require('zod');
|
|
5
8
|
var jsBase64 = require('js-base64');
|
|
6
|
-
var
|
|
9
|
+
var accounts = require('viem/accounts');
|
|
7
10
|
var zodOpenapi = require('zod-openapi');
|
|
8
11
|
|
|
12
|
+
function _interopNamespace(e) {
|
|
13
|
+
if (e && e.__esModule) return e;
|
|
14
|
+
var n = Object.create(null);
|
|
15
|
+
if (e) {
|
|
16
|
+
Object.keys(e).forEach(function (k) {
|
|
17
|
+
if (k !== 'default') {
|
|
18
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
19
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return e[k]; }
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
n.default = e;
|
|
27
|
+
return Object.freeze(n);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var z7__namespace = /*#__PURE__*/_interopNamespace(z7);
|
|
31
|
+
|
|
9
32
|
var __defProp = Object.defineProperty;
|
|
10
33
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
34
|
var __export = (target, all) => {
|
|
12
35
|
for (var name in all)
|
|
13
36
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
37
|
};
|
|
15
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
|
|
38
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
39
|
+
|
|
40
|
+
// src/api/Api/Schema/index.ts
|
|
41
|
+
var Schema_exports = {};
|
|
42
|
+
__export(Schema_exports, {
|
|
43
|
+
ChainHealth: () => ChainHealth,
|
|
44
|
+
ChainsHealthResponse: () => ChainsHealthResponse,
|
|
45
|
+
CollectorHealth: () => CollectorHealth,
|
|
46
|
+
CollectorsHealthResponse: () => CollectorsHealthResponse,
|
|
47
|
+
ObligationResponse: () => ObligationResponse_exports,
|
|
48
|
+
OfferResponse: () => OfferResponse_exports,
|
|
49
|
+
OpenApi: () => OpenApi,
|
|
50
|
+
RouterStatusResponse: () => RouterStatusResponse,
|
|
51
|
+
parse: () => parse,
|
|
52
|
+
safeParse: () => safeParse
|
|
53
|
+
});
|
|
54
|
+
var CollectorHealth = v4.z.object({
|
|
55
|
+
name: v4.z.string(),
|
|
56
|
+
chain_id: v4.z.number(),
|
|
57
|
+
block_number: v4.z.number().nullable(),
|
|
58
|
+
updated_at: v4.z.string().nullable(),
|
|
59
|
+
lag: v4.z.number().nullable(),
|
|
60
|
+
status: v4.z.enum(["live", "lagging", "unknown"])
|
|
61
|
+
});
|
|
62
|
+
var CollectorsHealthResponse = v4.z.object({
|
|
63
|
+
collectors: v4.z.array(CollectorHealth)
|
|
64
|
+
});
|
|
65
|
+
var ChainHealth = v4.z.object({
|
|
66
|
+
chain_id: v4.z.number(),
|
|
67
|
+
block_number: v4.z.number(),
|
|
68
|
+
updated_at: v4.z.string()
|
|
69
|
+
});
|
|
70
|
+
var ChainsHealthResponse = v4.z.object({
|
|
71
|
+
chains: v4.z.array(ChainHealth)
|
|
72
|
+
});
|
|
73
|
+
var RouterStatusResponse = v4.z.object({
|
|
74
|
+
status: v4.z.enum(["live", "syncing"])
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// src/api/Api/Schema/ObligationResponse.ts
|
|
78
|
+
var ObligationResponse_exports = {};
|
|
79
|
+
__export(ObligationResponse_exports, {
|
|
80
|
+
from: () => from6
|
|
81
|
+
});
|
|
82
|
+
|
|
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
|
|
91
|
+
});
|
|
92
|
+
var Oracle = [
|
|
93
|
+
{
|
|
94
|
+
type: "function",
|
|
95
|
+
name: "price",
|
|
96
|
+
inputs: [],
|
|
97
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
98
|
+
stateMutability: "view"
|
|
99
|
+
}
|
|
100
|
+
];
|
|
101
|
+
var ERC4626 = [
|
|
102
|
+
{
|
|
103
|
+
type: "function",
|
|
104
|
+
name: "asset",
|
|
105
|
+
inputs: [],
|
|
106
|
+
outputs: [{ name: "", type: "address" }],
|
|
107
|
+
stateMutability: "view"
|
|
108
|
+
}
|
|
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"
|
|
117
|
+
}
|
|
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"
|
|
140
|
+
}
|
|
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"
|
|
273
|
+
}
|
|
274
|
+
];
|
|
16
275
|
|
|
17
276
|
// src/core/Callback.ts
|
|
18
277
|
var Callback_exports = {};
|
|
19
278
|
__export(Callback_exports, {
|
|
20
279
|
CallbackType: () => CallbackType,
|
|
21
280
|
WhitelistedCallbackAddresses: () => WhitelistedCallbackAddresses,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
281
|
+
decodeBuyVaultV1Callback: () => decodeBuyVaultV1Callback,
|
|
282
|
+
decodeSellERC20Callback: () => decodeSellERC20Callback,
|
|
283
|
+
encodeBuyVaultV1Callback: () => encodeBuyVaultV1Callback,
|
|
284
|
+
encodeSellERC20Callback: () => encodeSellERC20Callback
|
|
26
285
|
});
|
|
27
286
|
var CallbackType = /* @__PURE__ */ ((CallbackType2) => {
|
|
28
287
|
CallbackType2["BuyWithEmptyCallback"] = "buy_with_empty_callback";
|
|
29
|
-
CallbackType2["
|
|
288
|
+
CallbackType2["BuyVaultV1Callback"] = "buy_vault_v1_callback";
|
|
289
|
+
CallbackType2["SellERC20Callback"] = "sell_erc20_callback";
|
|
30
290
|
return CallbackType2;
|
|
31
291
|
})(CallbackType || {});
|
|
32
292
|
var WhitelistedCallbackAddresses = {
|
|
33
293
|
["buy_with_empty_callback" /* BuyWithEmptyCallback */]: [],
|
|
34
|
-
["
|
|
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 */]: [
|
|
35
300
|
"0x1111111111111111111111111111111111111111",
|
|
36
301
|
"0x2222222222222222222222222222222222222222"
|
|
37
302
|
// @TODO: update once deployed and add mapping per chain if needed
|
|
38
303
|
].map((address) => address.toLowerCase())
|
|
39
304
|
};
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
id,
|
|
50
|
-
availableLiquidityQueueId: id,
|
|
51
|
-
user: user.toLowerCase(),
|
|
52
|
-
chainId,
|
|
53
|
-
amount: amountStr,
|
|
54
|
-
updatedAt
|
|
55
|
-
},
|
|
56
|
-
queues: [
|
|
57
|
-
{
|
|
58
|
-
queue: {
|
|
59
|
-
queueId: id,
|
|
60
|
-
availableLiquidityPoolId: poolId,
|
|
61
|
-
index,
|
|
62
|
-
callbackAmount: "0",
|
|
63
|
-
updatedAt
|
|
64
|
-
},
|
|
65
|
-
pool: {
|
|
66
|
-
id: poolId,
|
|
67
|
-
amount: amountStr,
|
|
68
|
-
updatedAt
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
]
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
case "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */: {
|
|
75
|
-
const {
|
|
76
|
-
user,
|
|
77
|
-
termId,
|
|
78
|
-
chainId,
|
|
79
|
-
amount,
|
|
80
|
-
collaterals,
|
|
81
|
-
index = 0,
|
|
82
|
-
updatedAt = /* @__PURE__ */ new Date()
|
|
83
|
-
} = parameters;
|
|
84
|
-
const amountStr = amount.toString();
|
|
85
|
-
const id = `${user}-${chainId.toString()}-${parameters.type}-${termId}`.toLowerCase();
|
|
86
|
-
return {
|
|
87
|
-
userPosition: {
|
|
88
|
-
id,
|
|
89
|
-
availableLiquidityQueueId: id,
|
|
90
|
-
user: user.toLowerCase(),
|
|
91
|
-
chainId,
|
|
92
|
-
amount: amountStr,
|
|
93
|
-
updatedAt
|
|
94
|
-
},
|
|
95
|
-
queues: collaterals.map((collateral) => {
|
|
96
|
-
const poolId = `${user}-${chainId.toString()}-${collateral.collateralAddress}`.toLowerCase();
|
|
97
|
-
return {
|
|
98
|
-
queue: {
|
|
99
|
-
queueId: id,
|
|
100
|
-
availableLiquidityPoolId: poolId,
|
|
101
|
-
index,
|
|
102
|
-
callbackAmount: collateral.callbackAmount.toString(),
|
|
103
|
-
updatedAt
|
|
104
|
-
},
|
|
105
|
-
pool: {
|
|
106
|
-
id: poolId,
|
|
107
|
-
amount: collateral.balance.toString(),
|
|
108
|
-
updatedAt
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
})
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
default: {
|
|
115
|
-
throw new Error(`CallbackType not implemented`);
|
|
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");
|
|
116
314
|
}
|
|
315
|
+
return vaults.map((v, i) => ({ vault: v, amount: amounts[i] }));
|
|
316
|
+
} catch (_) {
|
|
317
|
+
throw new Error("Invalid BuyVaultV1Callback callback data");
|
|
117
318
|
}
|
|
118
319
|
}
|
|
119
|
-
function
|
|
120
|
-
if (offer.buy && offer.callback.data === "0x") {
|
|
121
|
-
return `${offer.offering}-${offer.chainId.toString()}-${"buy_with_empty_callback" /* BuyWithEmptyCallback */}-${offer.loanToken}`.toLowerCase();
|
|
122
|
-
}
|
|
123
|
-
if (!offer.buy && offer.callback.data !== "0x" && WhitelistedCallbackAddresses["sell_withdraw_from_wallet" /* SellWithdrawFromWallet */].includes(
|
|
124
|
-
offer.callback.address.toLowerCase()
|
|
125
|
-
)) {
|
|
126
|
-
return `${offer.offering}-${offer.chainId.toString()}-${"sell_withdraw_from_wallet" /* SellWithdrawFromWallet */}-${mempool.Offer.termId(offer)}`.toLowerCase();
|
|
127
|
-
}
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
function decodeSellWithdrawFromWalletData(data) {
|
|
320
|
+
function decodeSellERC20Callback(data) {
|
|
131
321
|
if (!data || data === "0x") throw new Error("Empty callback data");
|
|
132
322
|
try {
|
|
133
323
|
const [collaterals, amounts] = viem.decodeAbiParameters(
|
|
@@ -139,32 +329,449 @@ function decodeSellWithdrawFromWalletData(data) {
|
|
|
139
329
|
}
|
|
140
330
|
return collaterals.map((c, i) => ({ collateral: c, amount: amounts[i] }));
|
|
141
331
|
} catch (_) {
|
|
142
|
-
throw new Error("Invalid
|
|
332
|
+
throw new Error("Invalid SellERC20Callback callback data");
|
|
143
333
|
}
|
|
144
334
|
}
|
|
145
|
-
function
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
335
|
+
function encodeBuyVaultV1Callback(parameters) {
|
|
336
|
+
return viem.encodeAbiParameters(
|
|
337
|
+
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
338
|
+
[parameters.vaults, parameters.amounts]
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
function encodeSellERC20Callback(parameters) {
|
|
342
|
+
return viem.encodeAbiParameters(
|
|
343
|
+
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
344
|
+
[parameters.collaterals, parameters.amounts]
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
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
|
+
});
|
|
363
|
+
|
|
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;
|
|
370
|
+
}
|
|
371
|
+
|
|
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);
|
|
149
376
|
}
|
|
150
|
-
throw new Error(`CallbackType not implemented: ${type}`);
|
|
151
377
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
378
|
+
|
|
379
|
+
// src/utils/Errors.ts
|
|
380
|
+
var Errors_exports = {};
|
|
381
|
+
__export(Errors_exports, {
|
|
382
|
+
BaseError: () => BaseError
|
|
383
|
+
});
|
|
384
|
+
var BaseError = class _BaseError extends Error {
|
|
385
|
+
constructor(shortMessage, options = {}) {
|
|
386
|
+
const details = (() => {
|
|
387
|
+
if (options.cause instanceof _BaseError) {
|
|
388
|
+
if (options.cause.details) return options.cause.details;
|
|
389
|
+
if (options.cause.shortMessage) return options.cause.shortMessage;
|
|
390
|
+
}
|
|
391
|
+
if (options.cause && "details" in options.cause && typeof options.cause.details === "string")
|
|
392
|
+
return options.cause.details;
|
|
393
|
+
if (options.cause?.message) return options.cause.message;
|
|
394
|
+
return options.details;
|
|
395
|
+
})();
|
|
396
|
+
const message = [
|
|
397
|
+
shortMessage || "An error occurred.",
|
|
398
|
+
...options.metaMessages ? ["", ...options.metaMessages] : [],
|
|
399
|
+
...details ? ["", details ? `Details: ${details}` : void 0] : []
|
|
400
|
+
].filter((x) => typeof x === "string").join("\n");
|
|
401
|
+
super(message, options.cause ? { cause: options.cause } : void 0);
|
|
402
|
+
__publicField(this, "details");
|
|
403
|
+
__publicField(this, "shortMessage");
|
|
404
|
+
__publicField(this, "cause");
|
|
405
|
+
__publicField(this, "name", "BaseError");
|
|
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;
|
|
418
|
+
}
|
|
419
|
+
|
|
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
|
+
].map((address) => address.toLowerCase())
|
|
453
|
+
),
|
|
454
|
+
morpho: "0x0000000000000000000000000000000000000000",
|
|
455
|
+
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
456
|
+
mempool: {
|
|
457
|
+
address: "0x0000000000000000000000000000000000000000",
|
|
458
|
+
deploymentBlock: 23347674,
|
|
459
|
+
reindexBuffer: 10
|
|
460
|
+
},
|
|
461
|
+
vaultV1Factory: {
|
|
462
|
+
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
463
|
+
"v1.1": "0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
base: {
|
|
467
|
+
...chains$1.base,
|
|
468
|
+
id: ChainId.BASE,
|
|
469
|
+
name: "base",
|
|
470
|
+
whitelistedAssets: new Set(
|
|
471
|
+
[
|
|
472
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
473
|
+
// USDC
|
|
474
|
+
"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb"
|
|
475
|
+
// DAI
|
|
476
|
+
].map((address) => address.toLowerCase())
|
|
477
|
+
),
|
|
478
|
+
morpho: "0x0000000000000000000000000000000000000000",
|
|
479
|
+
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
480
|
+
mempool: {
|
|
481
|
+
address: "0x0000000000000000000000000000000000000000",
|
|
482
|
+
deploymentBlock: 35449942,
|
|
483
|
+
reindexBuffer: 10
|
|
484
|
+
},
|
|
485
|
+
vaultV1Factory: {
|
|
486
|
+
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
487
|
+
"v1.1": "0xFf62A7c278C62eD665133147129245053Bbf5918"
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
"ethereum-virtual-testnet": {
|
|
491
|
+
...chains$1.mainnet,
|
|
492
|
+
id: ChainId["ETHEREUM-VIRTUAL-TESTNET"],
|
|
493
|
+
name: "ethereum-virtual-testnet",
|
|
494
|
+
whitelistedAssets: new Set(
|
|
495
|
+
[
|
|
496
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
497
|
+
// USDC
|
|
498
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
|
499
|
+
// DAI
|
|
500
|
+
].map((address) => address.toLowerCase())
|
|
501
|
+
),
|
|
502
|
+
morpho: "0x11a002d45db720ed47a80d2f3489cba5b833eaf5",
|
|
503
|
+
// @TODO: This is mock Consumed contract, update with Terms once stable
|
|
504
|
+
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
505
|
+
mempool: {
|
|
506
|
+
address: "0x5b06224f736a57635b5bcb50b8ef178b189107cb",
|
|
507
|
+
deploymentBlock: 23224302,
|
|
508
|
+
reindexBuffer: 10
|
|
509
|
+
},
|
|
510
|
+
vaultV1Factory: {
|
|
511
|
+
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
512
|
+
"v1.1": "0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
anvil: {
|
|
516
|
+
...chains$1.anvil,
|
|
517
|
+
id: ChainId.ANVIL,
|
|
518
|
+
name: "anvil",
|
|
519
|
+
whitelistedAssets: new Set(
|
|
520
|
+
[
|
|
521
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
522
|
+
// USDC
|
|
523
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
|
524
|
+
// DAI
|
|
525
|
+
].map((address) => address.toLowerCase())
|
|
526
|
+
),
|
|
527
|
+
morpho: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
|
|
528
|
+
morphoBlue: "0x0000000000000000000000000000000000000000",
|
|
529
|
+
// Set dynamically in tests
|
|
530
|
+
mempool: {
|
|
531
|
+
address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
|
|
532
|
+
deploymentBlock: 23223727,
|
|
533
|
+
reindexBuffer: 10
|
|
534
|
+
},
|
|
535
|
+
vaultV1Factory: {
|
|
536
|
+
"v1.0": "0x0000000000000000000000000000000000000000",
|
|
537
|
+
"v1.1": "0x0000000000000000000000000000000000000000"
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
var MAX_BATCH_SIZE = 1e4;
|
|
542
|
+
var DEFAULT_BATCH_SIZE = 2500;
|
|
543
|
+
var MAX_BLOCK_WINDOW = 2e3;
|
|
544
|
+
var DEFAULT_BLOCK_WINDOW = 500;
|
|
545
|
+
async function* streamLogs(parameters) {
|
|
546
|
+
const {
|
|
547
|
+
client,
|
|
548
|
+
contractAddress,
|
|
549
|
+
event,
|
|
550
|
+
blockNumberGte,
|
|
551
|
+
blockNumberLte,
|
|
552
|
+
order = "desc",
|
|
553
|
+
options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = DEFAULT_BLOCK_WINDOW } = {}
|
|
554
|
+
} = parameters;
|
|
555
|
+
if (maxBatchSize > MAX_BATCH_SIZE) throw new InvalidBatchSizeError(maxBatchSize);
|
|
556
|
+
if (blockWindow > MAX_BLOCK_WINDOW) throw new InvalidBlockWindowError(blockWindow);
|
|
557
|
+
if (order === "asc" && blockNumberGte === void 0) throw new MissingBlockNumberError();
|
|
558
|
+
const latestBlock = (await actions.getBlock(client, { blockTag: "latest", includeTransactions: false })).number;
|
|
559
|
+
let toBlock = 0n;
|
|
560
|
+
if (order === "asc")
|
|
561
|
+
toBlock = min(BigInt(blockNumberGte) + BigInt(blockWindow), latestBlock);
|
|
562
|
+
if (order === "desc")
|
|
563
|
+
toBlock = blockNumberLte === void 0 ? latestBlock : min(BigInt(blockNumberLte), latestBlock);
|
|
564
|
+
let fromBlock = 0n;
|
|
565
|
+
if (order === "asc") fromBlock = min(BigInt(blockNumberGte), latestBlock);
|
|
566
|
+
if (order === "desc")
|
|
567
|
+
fromBlock = max(BigInt(blockNumberGte || toBlock - BigInt(blockWindow)), 0n);
|
|
568
|
+
if (order === "asc") toBlock = min(toBlock, fromBlock + BigInt(blockWindow));
|
|
569
|
+
if (order === "desc") fromBlock = max(fromBlock, toBlock - BigInt(blockWindow));
|
|
570
|
+
if (fromBlock > toBlock) throw new InvalidBlockRangeError(fromBlock, toBlock);
|
|
571
|
+
let streaming = true;
|
|
572
|
+
while (streaming) {
|
|
573
|
+
const logs = await actions.getLogs(client, {
|
|
574
|
+
address: contractAddress,
|
|
575
|
+
event,
|
|
576
|
+
fromBlock,
|
|
577
|
+
toBlock
|
|
578
|
+
});
|
|
579
|
+
logs.sort((a, b) => {
|
|
580
|
+
if (a.blockNumber !== b.blockNumber)
|
|
581
|
+
return order === "asc" ? Number(a.blockNumber - b.blockNumber) : Number(b.blockNumber - a.blockNumber);
|
|
582
|
+
if (a.transactionIndex !== b.transactionIndex)
|
|
583
|
+
return order === "asc" ? a.transactionIndex - b.transactionIndex : b.transactionIndex - a.transactionIndex;
|
|
584
|
+
return order === "asc" ? a.logIndex - b.logIndex : b.logIndex - a.logIndex;
|
|
585
|
+
});
|
|
586
|
+
for (const logBatch of batch(logs, maxBatchSize)) {
|
|
587
|
+
if (logBatch.length === 0) break;
|
|
588
|
+
yield {
|
|
589
|
+
logs: logBatch,
|
|
590
|
+
blockNumber: logBatch.length === maxBatchSize ? (
|
|
591
|
+
// if the batch is full, return the last block number, block numbers are always sorted
|
|
592
|
+
Number(logBatch[logBatch.length - 1]?.blockNumber)
|
|
593
|
+
) : (
|
|
594
|
+
// if the batch is not full, return `toBlock` or `fromBlock` to indicate until which block the logs were fetched
|
|
595
|
+
order === "asc" ? Number(toBlock) : Number(fromBlock)
|
|
596
|
+
)
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
streaming = order === "asc" ? toBlock < (blockNumberLte || latestBlock) : fromBlock > (blockNumberGte || 0n);
|
|
600
|
+
if (order === "asc") {
|
|
601
|
+
fromBlock = min(BigInt(toBlock) + 1n, latestBlock);
|
|
602
|
+
toBlock = min(fromBlock + BigInt(blockWindow), latestBlock);
|
|
603
|
+
}
|
|
604
|
+
if (order === "desc") {
|
|
605
|
+
const lowerBound = BigInt(blockNumberGte || 0);
|
|
606
|
+
const windowSize = BigInt(blockWindow);
|
|
607
|
+
const nextToBlock = max(fromBlock - 1n, lowerBound);
|
|
608
|
+
const nextFromBlock = max(nextToBlock - windowSize, lowerBound);
|
|
609
|
+
toBlock = nextToBlock;
|
|
610
|
+
fromBlock = nextFromBlock;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
yield { logs: [], blockNumber: order === "asc" ? Number(toBlock) : Number(fromBlock) };
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
var InvalidBlockRangeError = class extends BaseError {
|
|
617
|
+
constructor(fromBlock, toBlock) {
|
|
618
|
+
super(
|
|
619
|
+
`Invalid block range while streaming data from chain. From block ${fromBlock} to block ${toBlock}.`
|
|
158
620
|
);
|
|
621
|
+
__publicField(this, "name", "Chain.InvalidBlockRangeError");
|
|
159
622
|
}
|
|
160
|
-
|
|
623
|
+
};
|
|
624
|
+
var InvalidBlockWindowError = class extends BaseError {
|
|
625
|
+
constructor(blockWindow) {
|
|
626
|
+
super(
|
|
627
|
+
`Invalid block window while streaming data from chain. Maximum is ${MAX_BLOCK_WINDOW}. Got ${blockWindow}.`
|
|
628
|
+
);
|
|
629
|
+
__publicField(this, "name", "Chain.InvalidBlockWindowError");
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
var InvalidBatchSizeError = class extends BaseError {
|
|
633
|
+
constructor(maxBatchSize) {
|
|
634
|
+
super(
|
|
635
|
+
`Invalid batch size while streaming data from chain. Maximum is ${MAX_BATCH_SIZE}. Got ${maxBatchSize}.`
|
|
636
|
+
);
|
|
637
|
+
__publicField(this, "name", "Chain.InvalidBatchSizeError");
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
var MissingBlockNumberError = class extends BaseError {
|
|
641
|
+
constructor() {
|
|
642
|
+
super("Missing block number when streaming data from chain in ascending order.");
|
|
643
|
+
__publicField(this, "name", "Chain.MissingBlockNumberError");
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
|
|
647
|
+
// src/core/Collateral.ts
|
|
648
|
+
var Collateral_exports = {};
|
|
649
|
+
__export(Collateral_exports, {
|
|
650
|
+
CollateralSchema: () => CollateralSchema,
|
|
651
|
+
CollateralsSchema: () => CollateralsSchema,
|
|
652
|
+
from: () => from2
|
|
653
|
+
});
|
|
654
|
+
var transformHex = (val, ctx) => {
|
|
655
|
+
if (viem.isHex(val)) return val;
|
|
656
|
+
ctx.addIssue({
|
|
657
|
+
code: "invalid_format",
|
|
658
|
+
input: val,
|
|
659
|
+
format: "hex",
|
|
660
|
+
error: "not a hex"
|
|
661
|
+
});
|
|
662
|
+
return z7__namespace.NEVER;
|
|
663
|
+
};
|
|
664
|
+
var transformAddress = (val, ctx) => {
|
|
665
|
+
if (viem.isAddress(val.toLowerCase())) return val.toLowerCase();
|
|
666
|
+
ctx.addIssue({
|
|
667
|
+
code: "invalid_format",
|
|
668
|
+
input: val,
|
|
669
|
+
format: "address",
|
|
670
|
+
error: "not a valid address"
|
|
671
|
+
});
|
|
672
|
+
return z7__namespace.NEVER;
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
// src/core/LLTV.ts
|
|
676
|
+
var LLTV_exports = {};
|
|
677
|
+
__export(LLTV_exports, {
|
|
678
|
+
InvalidLLTVError: () => InvalidLLTVError,
|
|
679
|
+
InvalidOptionError: () => InvalidOptionError,
|
|
680
|
+
LLTVSchema: () => LLTVSchema,
|
|
681
|
+
Options: () => Options,
|
|
682
|
+
from: () => from
|
|
683
|
+
});
|
|
684
|
+
var Options = [0.385, 0.5, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965, 0.98];
|
|
685
|
+
var LLTV_SCALED = Options.map((lltv) => BigInt(lltv * 10 ** 18));
|
|
686
|
+
function from(lltv) {
|
|
687
|
+
if (typeof lltv === "bigint" && !LLTV_SCALED.includes(lltv)) throw new InvalidLLTVError(lltv);
|
|
688
|
+
if (typeof lltv === "bigint") return lltv;
|
|
689
|
+
if (typeof lltv === "number" && !Options.includes(lltv)) throw new InvalidOptionError(lltv);
|
|
690
|
+
return BigInt(lltv * 10 ** 18);
|
|
161
691
|
}
|
|
692
|
+
var InvalidOptionError = class extends BaseError {
|
|
693
|
+
constructor(input) {
|
|
694
|
+
super(
|
|
695
|
+
`Invalid LLTV option. Input: "${input}". Accepted values are: ${Options.map(
|
|
696
|
+
(option) => `"${option}"`
|
|
697
|
+
).join(", ")}.`
|
|
698
|
+
);
|
|
699
|
+
__publicField(this, "name", "LLTV.InvalidOptionError");
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
var InvalidLLTVError = class extends BaseError {
|
|
703
|
+
constructor(input) {
|
|
704
|
+
super(
|
|
705
|
+
`Invalid LLTV. Input: "${input}". Accepted values are: ${LLTV_SCALED.map(
|
|
706
|
+
(option) => `"${option}"`
|
|
707
|
+
).join(", ")}.`
|
|
708
|
+
);
|
|
709
|
+
__publicField(this, "name", "LLTV.InvalidLLTVError");
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
var LLTVSchema = z7__namespace.bigint({ coerce: true }).refine(
|
|
713
|
+
(lltv) => {
|
|
714
|
+
try {
|
|
715
|
+
from(lltv);
|
|
716
|
+
return true;
|
|
717
|
+
} catch (_) {
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
},
|
|
721
|
+
{
|
|
722
|
+
error: () => {
|
|
723
|
+
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)";
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
).transform((lltv) => from(lltv));
|
|
727
|
+
|
|
728
|
+
// src/core/Collateral.ts
|
|
729
|
+
var CollateralSchema = z7__namespace.object({
|
|
730
|
+
asset: z7__namespace.string().transform(transformAddress),
|
|
731
|
+
oracle: z7__namespace.string().transform(transformAddress),
|
|
732
|
+
lltv: LLTVSchema
|
|
733
|
+
});
|
|
734
|
+
var CollateralsSchema = z7__namespace.array(CollateralSchema).min(1, { message: "At least one collateral is required" }).refine(
|
|
735
|
+
(collaterals) => {
|
|
736
|
+
for (let i = 1; i < collaterals.length; i++) {
|
|
737
|
+
if (collaterals[i - 1].asset.toLowerCase() > collaterals[i].asset.toLowerCase()) {
|
|
738
|
+
return false;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return true;
|
|
742
|
+
},
|
|
743
|
+
{
|
|
744
|
+
message: "Collaterals must be sorted alphabetically by address"
|
|
745
|
+
}
|
|
746
|
+
).refine(
|
|
747
|
+
(collaterals) => {
|
|
748
|
+
const uniqueAssets = /* @__PURE__ */ new Set();
|
|
749
|
+
for (const collateral of collaterals) {
|
|
750
|
+
const assetAddress = collateral.asset.toLowerCase();
|
|
751
|
+
if (uniqueAssets.has(assetAddress)) {
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
uniqueAssets.add(assetAddress);
|
|
755
|
+
}
|
|
756
|
+
return true;
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
message: "Collaterals must not contain duplicate assets"
|
|
760
|
+
}
|
|
761
|
+
);
|
|
762
|
+
var from2 = (parameters) => {
|
|
763
|
+
return {
|
|
764
|
+
asset: parameters.asset.toLowerCase(),
|
|
765
|
+
lltv: from(parameters.lltv),
|
|
766
|
+
oracle: parameters.oracle.toLowerCase()
|
|
767
|
+
};
|
|
768
|
+
};
|
|
162
769
|
|
|
163
770
|
// src/core/Cursor.ts
|
|
164
771
|
var Cursor_exports = {};
|
|
165
772
|
__export(Cursor_exports, {
|
|
166
|
-
decode: () =>
|
|
167
|
-
encode: () =>
|
|
773
|
+
decode: () => decode,
|
|
774
|
+
encode: () => encode,
|
|
168
775
|
validate: () => validate
|
|
169
776
|
});
|
|
170
777
|
function validate(cursor) {
|
|
@@ -234,12 +841,17 @@ function validate(cursor) {
|
|
|
234
841
|
`Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
|
|
235
842
|
);
|
|
236
843
|
}
|
|
844
|
+
if (c.page !== void 0) {
|
|
845
|
+
if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
|
|
846
|
+
throw new Error("Invalid page: must be a positive integer");
|
|
847
|
+
}
|
|
848
|
+
}
|
|
237
849
|
return true;
|
|
238
850
|
}
|
|
239
|
-
function
|
|
851
|
+
function encode(c) {
|
|
240
852
|
return jsBase64.Base64.encodeURL(JSON.stringify(c));
|
|
241
853
|
}
|
|
242
|
-
function
|
|
854
|
+
function decode(token) {
|
|
243
855
|
if (!token) return null;
|
|
244
856
|
const decoded = JSON.parse(jsBase64.Base64.decode(token));
|
|
245
857
|
validate(decoded);
|
|
@@ -249,578 +861,780 @@ function decode2(token) {
|
|
|
249
861
|
// src/core/Liquidity.ts
|
|
250
862
|
var Liquidity_exports = {};
|
|
251
863
|
__export(Liquidity_exports, {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
864
|
+
calculateMaxDebt: () => calculateMaxDebt,
|
|
865
|
+
generateAllowancePoolId: () => generateAllowancePoolId,
|
|
866
|
+
generateBalancePoolId: () => generateBalancePoolId,
|
|
867
|
+
generateBuyVaultCallbackPoolId: () => generateBuyVaultCallbackPoolId,
|
|
868
|
+
generateDebtPoolId: () => generateDebtPoolId,
|
|
869
|
+
generateMarketLiquidityPoolId: () => generateMarketLiquidityPoolId,
|
|
870
|
+
generateObligationCollateralPoolId: () => generateObligationCollateralPoolId,
|
|
871
|
+
generateSellERC20CallbackPoolId: () => generateSellERC20CallbackPoolId,
|
|
872
|
+
generateUserVaultPositionPoolId: () => generateUserVaultPositionPoolId,
|
|
873
|
+
generateVaultPositionPoolId: () => generateVaultPositionPoolId
|
|
255
874
|
});
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
875
|
+
function calculateMaxDebt(amount, oraclePrice, lltv) {
|
|
876
|
+
const ORACLE_PRICE_SCALE = 10n ** 36n;
|
|
877
|
+
const PRECISION = 10n ** 18n;
|
|
878
|
+
const collateralQuoted = amount * oraclePrice / ORACLE_PRICE_SCALE;
|
|
879
|
+
const maxDebt = collateralQuoted * lltv / PRECISION;
|
|
880
|
+
return maxDebt;
|
|
881
|
+
}
|
|
882
|
+
function generateBalancePoolId(parameters) {
|
|
883
|
+
const { user, chainId, token } = parameters;
|
|
884
|
+
return `${user}-${chainId.toString()}-${token}-balance`.toLowerCase();
|
|
885
|
+
}
|
|
886
|
+
function generateAllowancePoolId(parameters) {
|
|
887
|
+
const { user, chainId, token } = parameters;
|
|
888
|
+
return `${user}-${chainId.toString()}-${token}-allowance`.toLowerCase();
|
|
889
|
+
}
|
|
890
|
+
function generateSellERC20CallbackPoolId(parameters) {
|
|
891
|
+
const { user, chainId, obligationId: obligationId2, token, offerHash } = parameters;
|
|
892
|
+
return `${user}-${chainId.toString()}-${obligationId2}-${token}-${offerHash}-sell_erc20_callback`.toLowerCase();
|
|
893
|
+
}
|
|
894
|
+
function generateObligationCollateralPoolId(parameters) {
|
|
895
|
+
const { user, chainId, obligationId: obligationId2, token } = parameters;
|
|
896
|
+
return `${user}-${chainId.toString()}-${obligationId2}-${token}-obligation-collateral`.toLowerCase();
|
|
897
|
+
}
|
|
898
|
+
function generateBuyVaultCallbackPoolId(parameters) {
|
|
899
|
+
const { user, chainId, vault, offerHash } = parameters;
|
|
900
|
+
return `${user}-${chainId.toString()}-${vault}-${offerHash}-${"buy_vault_v1_callback" /* BuyVaultV1Callback */}`.toLowerCase();
|
|
901
|
+
}
|
|
902
|
+
function generateDebtPoolId(parameters) {
|
|
903
|
+
const { user, chainId, obligationId: obligationId2 } = parameters;
|
|
904
|
+
return `${user}-${chainId.toString()}-${obligationId2}-debt`.toLowerCase();
|
|
905
|
+
}
|
|
906
|
+
function generateUserVaultPositionPoolId(parameters) {
|
|
907
|
+
const { user, chainId, vault } = parameters;
|
|
908
|
+
return `${user}-${chainId.toString()}-${vault}-user-vault-position`.toLowerCase();
|
|
909
|
+
}
|
|
910
|
+
function generateVaultPositionPoolId(parameters) {
|
|
911
|
+
const { vault, chainId, marketId } = parameters;
|
|
912
|
+
return `${vault}-${chainId.toString()}-${marketId}-vault-position`.toLowerCase();
|
|
913
|
+
}
|
|
914
|
+
function generateMarketLiquidityPoolId(parameters) {
|
|
915
|
+
const { chainId, marketId } = parameters;
|
|
916
|
+
return `${chainId.toString()}-${marketId}-market-liquidity`.toLowerCase();
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// src/core/Maturity.ts
|
|
920
|
+
var Maturity_exports = {};
|
|
921
|
+
__export(Maturity_exports, {
|
|
922
|
+
InvalidDateError: () => InvalidDateError,
|
|
923
|
+
InvalidFormatError: () => InvalidFormatError,
|
|
924
|
+
InvalidOptionError: () => InvalidOptionError2,
|
|
925
|
+
MaturitySchema: () => MaturitySchema,
|
|
926
|
+
from: () => from3
|
|
927
|
+
});
|
|
928
|
+
var MaturitySchema = z7__namespace.number().int().refine(
|
|
929
|
+
(maturity) => {
|
|
930
|
+
try {
|
|
931
|
+
from3(maturity);
|
|
932
|
+
return true;
|
|
933
|
+
} catch (_e) {
|
|
934
|
+
return false;
|
|
280
935
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
retryDelayMs
|
|
290
|
-
),
|
|
291
|
-
mempool.Utils.retry(
|
|
292
|
-
() => client.multicall({
|
|
293
|
-
allowFailure: false,
|
|
294
|
-
contracts: allowanceContracts,
|
|
295
|
-
...blockNumber ? { blockNumber } : {}
|
|
296
|
-
}),
|
|
297
|
-
retryAttempts,
|
|
298
|
-
retryDelayMs
|
|
299
|
-
)
|
|
300
|
-
]);
|
|
301
|
-
for (let i = 0; i < pairsBatch.length; i++) {
|
|
302
|
-
const { user, token } = pairsBatch[i];
|
|
303
|
-
const balance = balances[i];
|
|
304
|
-
const allowance = allowances[i];
|
|
305
|
-
let perUser = out.get(user);
|
|
306
|
-
if (!perUser) {
|
|
307
|
-
perUser = /* @__PURE__ */ new Map();
|
|
308
|
-
out.set(user, perUser);
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
error: (issue) => {
|
|
939
|
+
try {
|
|
940
|
+
const maturityDate = new Date(issue.input * 1e3);
|
|
941
|
+
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).`;
|
|
942
|
+
} catch (_) {
|
|
943
|
+
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).`;
|
|
309
944
|
}
|
|
310
|
-
perUser.set(token, { balance, allowance });
|
|
311
945
|
}
|
|
312
946
|
}
|
|
313
|
-
|
|
947
|
+
).transform((maturity) => maturity);
|
|
948
|
+
var MaturityOptions = {
|
|
949
|
+
end_of_week: () => endOfWeek(),
|
|
950
|
+
end_of_next_week: () => endOfNextWeek(),
|
|
951
|
+
end_of_month: () => endOfMonth(),
|
|
952
|
+
end_of_next_month: () => endOfNextMonth(),
|
|
953
|
+
end_of_quarter: () => endOfQuarter(),
|
|
954
|
+
end_of_next_quarter: () => endOfNextQuarter()
|
|
955
|
+
};
|
|
956
|
+
function from3(ts) {
|
|
957
|
+
if (typeof ts === "string") {
|
|
958
|
+
if (ts in MaturityOptions) return MaturityOptions[ts]();
|
|
959
|
+
throw new InvalidOptionError2(ts);
|
|
960
|
+
}
|
|
961
|
+
if (typeof ts === "number" && ts > 1e12) throw new InvalidFormatError();
|
|
962
|
+
if (!Object.values(MaturityOptions).some((option) => option() === ts))
|
|
963
|
+
throw new InvalidDateError(ts);
|
|
964
|
+
return ts;
|
|
314
965
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
out.push(
|
|
330
|
-
buildLiquidity({
|
|
331
|
-
type,
|
|
332
|
-
user,
|
|
333
|
-
loanToken,
|
|
334
|
-
chainId,
|
|
335
|
-
amount,
|
|
336
|
-
index: 0
|
|
337
|
-
})
|
|
338
|
-
);
|
|
339
|
-
}
|
|
966
|
+
var endOfWeek = () => fridayOfWeek(0);
|
|
967
|
+
var endOfNextWeek = () => fridayOfWeek(1);
|
|
968
|
+
var endOfMonth = () => lastFridayOfMonth((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth());
|
|
969
|
+
var endOfNextMonth = () => lastFridayOfMonth((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth() + 1);
|
|
970
|
+
var endOfQuarter = () => lastFridayOfQuarter(0);
|
|
971
|
+
var endOfNextQuarter = () => lastFridayOfQuarter(1);
|
|
972
|
+
var fridayOfWeek = (weeksAhead = 0) => {
|
|
973
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
974
|
+
const today15H = new Date(
|
|
975
|
+
Date.UTC(now2.getUTCFullYear(), now2.getUTCMonth(), now2.getUTCDate(), 15)
|
|
976
|
+
);
|
|
977
|
+
let daysUntilFriday = (5 - today15H.getUTCDay() + 7) % 7;
|
|
978
|
+
if (daysUntilFriday === 0 && now2.getTime() >= today15H.getTime()) {
|
|
979
|
+
daysUntilFriday = 7;
|
|
340
980
|
}
|
|
341
|
-
|
|
981
|
+
const friday = new Date(today15H);
|
|
982
|
+
friday.setUTCDate(friday.getUTCDate() + daysUntilFriday + weeksAhead * 7);
|
|
983
|
+
return friday.getTime() / 1e3;
|
|
984
|
+
};
|
|
985
|
+
var lastFridayOfMonth = (year, month) => {
|
|
986
|
+
const lastDayOfMonth15H = new Date(Date.UTC(year, month + 1, 0, 15));
|
|
987
|
+
while (lastDayOfMonth15H.getUTCDay() !== 5) {
|
|
988
|
+
lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate() - 1);
|
|
989
|
+
}
|
|
990
|
+
const maturity = lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate()) / 1e3;
|
|
991
|
+
return maturity;
|
|
992
|
+
};
|
|
993
|
+
var lastFridayOfQuarter = (quartersAhead = 0) => {
|
|
994
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
995
|
+
const quarterIndex = Math.floor(now2.getUTCMonth() / 3) + quartersAhead;
|
|
996
|
+
const year = now2.getUTCFullYear() + Math.floor(quarterIndex / 4);
|
|
997
|
+
const quarter = quarterIndex % 4;
|
|
998
|
+
const lastMonth = quarter * 3 + 2;
|
|
999
|
+
return lastFridayOfMonth(year, lastMonth);
|
|
1000
|
+
};
|
|
1001
|
+
var InvalidFormatError = class extends BaseError {
|
|
1002
|
+
constructor() {
|
|
1003
|
+
super("Invalid maturity format. Maturity should be expressed in seconds.");
|
|
1004
|
+
__publicField(this, "name", "Maturity.InvalidFormatError");
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
var InvalidDateError = class extends BaseError {
|
|
1008
|
+
constructor(input) {
|
|
1009
|
+
super(
|
|
1010
|
+
`Invalid maturity date. Input: "${input}". Accepted values are: ${Object.values(
|
|
1011
|
+
MaturityOptions
|
|
1012
|
+
).map((option) => `"${option()}"`).join(", ")}.`
|
|
1013
|
+
);
|
|
1014
|
+
__publicField(this, "name", "Maturity.InvalidDateError");
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
var InvalidOptionError2 = class extends BaseError {
|
|
1018
|
+
constructor(input) {
|
|
1019
|
+
super(
|
|
1020
|
+
`Invalid maturity option. Input: "${input}". Accepted values are: ${Object.keys(
|
|
1021
|
+
MaturityOptions
|
|
1022
|
+
).map((option) => `"${option}"`).join(", ")}.`
|
|
1023
|
+
);
|
|
1024
|
+
__publicField(this, "name", "Maturity.InvalidOptionError");
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
|
|
1028
|
+
// src/core/Obligation.ts
|
|
1029
|
+
var Obligation_exports = {};
|
|
1030
|
+
__export(Obligation_exports, {
|
|
1031
|
+
CollateralsAreNotSortedError: () => CollateralsAreNotSortedError,
|
|
1032
|
+
InvalidObligationError: () => InvalidObligationError,
|
|
1033
|
+
ObligationSchema: () => ObligationSchema,
|
|
1034
|
+
from: () => from4,
|
|
1035
|
+
fromSnakeCase: () => fromSnakeCase2,
|
|
1036
|
+
id: () => id,
|
|
1037
|
+
random: () => random
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
// src/utils/Format.ts
|
|
1041
|
+
var Format_exports = {};
|
|
1042
|
+
__export(Format_exports, {
|
|
1043
|
+
fromSnakeCase: () => fromSnakeCase,
|
|
1044
|
+
toSnakeCase: () => toSnakeCase
|
|
1045
|
+
});
|
|
1046
|
+
function toSnakeCase(obj) {
|
|
1047
|
+
return stringifyBigint(
|
|
1048
|
+
processObject(
|
|
1049
|
+
obj,
|
|
1050
|
+
(s) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`),
|
|
1051
|
+
(value) => typeof value === "string" && viem.isAddress(value.toLowerCase()) ? viem.getAddress(value.toLowerCase()) : value
|
|
1052
|
+
)
|
|
1053
|
+
);
|
|
342
1054
|
}
|
|
343
|
-
function
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
1055
|
+
function fromSnakeCase(obj) {
|
|
1056
|
+
return processObject(
|
|
1057
|
+
obj,
|
|
1058
|
+
(s) => viem.isAddress(s.toLowerCase()) ? s : s.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),
|
|
1059
|
+
(value) => typeof value === "string" && viem.isAddress(value.toLowerCase()) ? value.toLowerCase() : value
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1062
|
+
function processObject(obj, fnKey, fnValue) {
|
|
1063
|
+
if (typeof obj !== "object" || obj === null) return obj;
|
|
1064
|
+
if (Array.isArray(obj)) return obj.map((item) => processObject(item, fnKey, fnValue));
|
|
1065
|
+
return Object.entries(obj).reduce(
|
|
1066
|
+
(acc, [key, value]) => {
|
|
1067
|
+
const newKey = fnKey(key);
|
|
1068
|
+
acc[newKey] = typeof value === "object" && value !== null ? processObject(value, fnKey, fnValue) : fnValue(value);
|
|
1069
|
+
return acc;
|
|
351
1070
|
},
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
1071
|
+
{}
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
function stringifyBigint(value) {
|
|
1075
|
+
if (typeof value === "bigint") return value.toString();
|
|
1076
|
+
if (Array.isArray(value)) return value.map(stringifyBigint);
|
|
1077
|
+
if (value && typeof value === "object") {
|
|
1078
|
+
const out = {};
|
|
1079
|
+
for (const [k, v] of Object.entries(value)) {
|
|
1080
|
+
out[k] = stringifyBigint(v);
|
|
1081
|
+
}
|
|
1082
|
+
return out;
|
|
1083
|
+
}
|
|
1084
|
+
return value;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// src/core/Obligation.ts
|
|
1088
|
+
var ObligationSchema = z7__namespace.object({
|
|
1089
|
+
chainId: z7__namespace.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
1090
|
+
loanToken: z7__namespace.string().transform(transformAddress),
|
|
1091
|
+
collaterals: CollateralsSchema,
|
|
1092
|
+
maturity: MaturitySchema
|
|
1093
|
+
});
|
|
1094
|
+
function from4(parameters) {
|
|
1095
|
+
try {
|
|
1096
|
+
const parsedObligation = ObligationSchema.parse({
|
|
1097
|
+
...parameters,
|
|
1098
|
+
maturity: from3(parameters.maturity)
|
|
1099
|
+
});
|
|
1100
|
+
return {
|
|
1101
|
+
chainId: parsedObligation.chainId,
|
|
1102
|
+
loanToken: parsedObligation.loanToken.toLowerCase(),
|
|
1103
|
+
collaterals: parsedObligation.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)),
|
|
1104
|
+
maturity: parsedObligation.maturity
|
|
1105
|
+
};
|
|
1106
|
+
} catch (error) {
|
|
1107
|
+
throw new InvalidObligationError(error);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
function fromSnakeCase2(input) {
|
|
1111
|
+
return from4(fromSnakeCase(input));
|
|
1112
|
+
}
|
|
1113
|
+
function id(obligation) {
|
|
1114
|
+
let lastAsset = "";
|
|
1115
|
+
for (const collateral of obligation.collaterals) {
|
|
1116
|
+
const newAsset = collateral.asset.toLowerCase();
|
|
1117
|
+
if (newAsset.localeCompare(lastAsset) < 0) throw new CollateralsAreNotSortedError();
|
|
1118
|
+
lastAsset = newAsset;
|
|
1119
|
+
}
|
|
1120
|
+
return viem.keccak256(
|
|
1121
|
+
viem.encodeAbiParameters(
|
|
1122
|
+
[
|
|
1123
|
+
{ type: "uint256" },
|
|
1124
|
+
{ type: "address" },
|
|
1125
|
+
{
|
|
1126
|
+
type: "tuple[]",
|
|
1127
|
+
components: [
|
|
1128
|
+
{ type: "address", name: "token" },
|
|
1129
|
+
{ type: "uint256", name: "lltv" },
|
|
1130
|
+
{ type: "address", name: "oracle" }
|
|
1131
|
+
]
|
|
1132
|
+
},
|
|
1133
|
+
{ type: "uint256" }
|
|
1134
|
+
],
|
|
1135
|
+
[
|
|
1136
|
+
obligation.chainId,
|
|
1137
|
+
obligation.loanToken.toLowerCase(),
|
|
1138
|
+
obligation.collaterals.map((c) => ({
|
|
1139
|
+
token: c.asset.toLowerCase(),
|
|
1140
|
+
lltv: c.lltv,
|
|
1141
|
+
oracle: c.oracle.toLowerCase()
|
|
1142
|
+
})),
|
|
1143
|
+
BigInt(obligation.maturity)
|
|
1144
|
+
]
|
|
378
1145
|
)
|
|
379
|
-
|
|
380
|
-
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
function random() {
|
|
1149
|
+
return from4({
|
|
1150
|
+
chainId: 1n,
|
|
1151
|
+
loanToken: accounts.privateKeyToAccount(accounts.generatePrivateKey()).address,
|
|
1152
|
+
collaterals: [
|
|
1153
|
+
from2({
|
|
1154
|
+
asset: accounts.privateKeyToAccount(accounts.generatePrivateKey()).address,
|
|
1155
|
+
oracle: accounts.privateKeyToAccount(accounts.generatePrivateKey()).address,
|
|
1156
|
+
lltv: 0.965
|
|
1157
|
+
})
|
|
1158
|
+
],
|
|
1159
|
+
maturity: from3("end_of_next_quarter")
|
|
1160
|
+
});
|
|
381
1161
|
}
|
|
1162
|
+
var InvalidObligationError = class extends BaseError {
|
|
1163
|
+
constructor(error) {
|
|
1164
|
+
super("Invalid obligation.", { cause: error });
|
|
1165
|
+
__publicField(this, "name", "Obligation.InvalidObligationError");
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
var CollateralsAreNotSortedError = class extends BaseError {
|
|
1169
|
+
constructor() {
|
|
1170
|
+
super("Collaterals are not sorted alphabetically by address.");
|
|
1171
|
+
__publicField(this, "name", "Obligation.CollateralsAreNotSortedError");
|
|
1172
|
+
}
|
|
1173
|
+
};
|
|
382
1174
|
|
|
383
|
-
// src/core/
|
|
384
|
-
var
|
|
385
|
-
__export(
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
1175
|
+
// src/core/Offer.ts
|
|
1176
|
+
var Offer_exports = {};
|
|
1177
|
+
__export(Offer_exports, {
|
|
1178
|
+
AccountNotSetError: () => AccountNotSetError,
|
|
1179
|
+
InvalidOfferError: () => InvalidOfferError,
|
|
1180
|
+
OfferHashSchema: () => OfferHashSchema,
|
|
1181
|
+
OfferSchema: () => OfferSchema,
|
|
389
1182
|
consumedEvent: () => consumedEvent,
|
|
390
|
-
|
|
1183
|
+
decode: () => decode2,
|
|
1184
|
+
domain: () => domain,
|
|
1185
|
+
encode: () => encode2,
|
|
1186
|
+
from: () => from5,
|
|
391
1187
|
fromConsumedLog: () => fromConsumedLog,
|
|
1188
|
+
fromSnakeCase: () => fromSnakeCase3,
|
|
1189
|
+
hash: () => hash,
|
|
1190
|
+
obligationId: () => obligationId,
|
|
1191
|
+
random: () => random2,
|
|
1192
|
+
sign: () => sign,
|
|
1193
|
+
toSnakeCase: () => toSnakeCase2,
|
|
1194
|
+
types: () => types
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
// src/utils/index.ts
|
|
1198
|
+
var utils_exports = {};
|
|
1199
|
+
__export(utils_exports, {
|
|
1200
|
+
BaseError: () => BaseError,
|
|
1201
|
+
Time: () => time_exports,
|
|
1202
|
+
batch: () => batch,
|
|
1203
|
+
batchMulticall: () => batchMulticall,
|
|
392
1204
|
fromSnakeCase: () => fromSnakeCase,
|
|
393
|
-
|
|
394
|
-
|
|
1205
|
+
lazy: () => lazy,
|
|
1206
|
+
max: () => max,
|
|
1207
|
+
min: () => min,
|
|
1208
|
+
poll: () => poll,
|
|
1209
|
+
retry: () => retry,
|
|
1210
|
+
toSnakeCase: () => toSnakeCase,
|
|
1211
|
+
wait: () => wait
|
|
395
1212
|
});
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
1213
|
+
|
|
1214
|
+
// src/utils/retry.ts
|
|
1215
|
+
var retry = async (fn, attempts = 3, delayMs = 50) => {
|
|
1216
|
+
let lastErr;
|
|
1217
|
+
for (let i = 0; i < attempts; i++) {
|
|
1218
|
+
try {
|
|
1219
|
+
return await fn();
|
|
1220
|
+
} catch (err) {
|
|
1221
|
+
lastErr = err;
|
|
1222
|
+
if (i < attempts - 1) await new Promise((r) => setTimeout(r, delayMs));
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
throw lastErr;
|
|
1226
|
+
};
|
|
1227
|
+
|
|
1228
|
+
// src/utils/batchMulticall.ts
|
|
1229
|
+
async function batchMulticall(parameters) {
|
|
1230
|
+
const { client, calls, batchSize, retryAttempts, retryDelayMs, blockNumber } = parameters;
|
|
1231
|
+
const results = [];
|
|
1232
|
+
for (const callsBatch of batch(calls, batchSize)) {
|
|
1233
|
+
const batchResults = await retry(
|
|
1234
|
+
() => client.multicall({
|
|
1235
|
+
allowFailure: false,
|
|
1236
|
+
contracts: callsBatch,
|
|
1237
|
+
...blockNumber ? { blockNumber } : {}
|
|
1238
|
+
}),
|
|
1239
|
+
retryAttempts,
|
|
1240
|
+
retryDelayMs
|
|
1241
|
+
);
|
|
1242
|
+
results.push(...batchResults);
|
|
1243
|
+
}
|
|
1244
|
+
return results;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
// src/utils/lazy.ts
|
|
1248
|
+
function lazy(pollFn) {
|
|
1249
|
+
return () => async function* () {
|
|
1250
|
+
let active = true;
|
|
1251
|
+
let resolveNext = null;
|
|
1252
|
+
const queue = [];
|
|
1253
|
+
const wait2 = () => new Promise((resolve) => {
|
|
1254
|
+
resolveNext = resolve;
|
|
1255
|
+
});
|
|
1256
|
+
const emit = (item) => {
|
|
1257
|
+
queue.push(item);
|
|
1258
|
+
resolveNext?.();
|
|
1259
|
+
resolveNext = null;
|
|
1260
|
+
};
|
|
1261
|
+
let unpoll = null;
|
|
1262
|
+
const stop = () => {
|
|
1263
|
+
active = false;
|
|
1264
|
+
unpoll?.();
|
|
1265
|
+
resolveNext?.();
|
|
1266
|
+
resolveNext = null;
|
|
1267
|
+
};
|
|
1268
|
+
unpoll = pollFn(emit, { stop });
|
|
1269
|
+
try {
|
|
1270
|
+
while (active) {
|
|
1271
|
+
if (queue.length === 0) await wait2();
|
|
1272
|
+
while (queue.length > 0 && active) yield queue.shift();
|
|
1273
|
+
}
|
|
1274
|
+
} finally {
|
|
1275
|
+
stop();
|
|
1276
|
+
}
|
|
1277
|
+
}();
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// src/utils/wait.ts
|
|
1281
|
+
async function wait(time) {
|
|
1282
|
+
return new Promise((res) => setTimeout(res, time));
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
// src/utils/poll.ts
|
|
1286
|
+
function poll(fn, { interval }) {
|
|
1287
|
+
let active = true;
|
|
1288
|
+
const unwatch = () => active = false;
|
|
1289
|
+
const watch2 = async () => {
|
|
1290
|
+
await wait(interval);
|
|
1291
|
+
const poll2 = async () => {
|
|
1292
|
+
if (!active) return;
|
|
1293
|
+
await fn({ unpoll: unwatch });
|
|
1294
|
+
await wait(interval);
|
|
1295
|
+
poll2();
|
|
1296
|
+
};
|
|
1297
|
+
poll2();
|
|
1298
|
+
};
|
|
1299
|
+
watch2();
|
|
1300
|
+
return unwatch;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// src/utils/time.ts
|
|
1304
|
+
var time_exports = {};
|
|
1305
|
+
__export(time_exports, {
|
|
1306
|
+
max: () => max2,
|
|
1307
|
+
now: () => now
|
|
408
1308
|
});
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
1309
|
+
function now() {
|
|
1310
|
+
return Math.floor(Date.now() / 1e3);
|
|
1311
|
+
}
|
|
1312
|
+
function max2() {
|
|
1313
|
+
return 864e16;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// src/core/Offer.ts
|
|
1317
|
+
var OfferHashSchema = z7__namespace.string().regex(/^0x[0-9a-fA-F]{64}$/, {
|
|
1318
|
+
message: "Hash must be a valid 32-byte hex string"
|
|
1319
|
+
}).transform(transformHex);
|
|
1320
|
+
var OfferSchema = (parameters) => {
|
|
1321
|
+
const { omitHash = false } = parameters || {};
|
|
1322
|
+
const now2 = time_exports.now();
|
|
1323
|
+
let base = z7__namespace.object({
|
|
1324
|
+
offering: z7__namespace.string().transform(transformAddress),
|
|
1325
|
+
assets: z7__namespace.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
1326
|
+
rate: z7__namespace.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
1327
|
+
maturity: MaturitySchema,
|
|
1328
|
+
expiry: z7__namespace.number().int().min(now2, { message: "Expiry must be set to a future date" }).max(Number.MAX_SAFE_INTEGER),
|
|
1329
|
+
start: z7__namespace.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
1330
|
+
nonce: z7__namespace.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
1331
|
+
buy: z7__namespace.boolean(),
|
|
1332
|
+
chainId: z7__namespace.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
1333
|
+
loanToken: z7__namespace.string().transform(transformAddress),
|
|
1334
|
+
collaterals: CollateralsSchema,
|
|
1335
|
+
callback: z7__namespace.object({
|
|
1336
|
+
address: z7__namespace.string().transform(transformAddress),
|
|
1337
|
+
data: z7__namespace.string().transform(transformHex),
|
|
1338
|
+
gasLimit: z7__namespace.bigint({ coerce: true }).min(0n).max(viem.maxUint256)
|
|
1339
|
+
}),
|
|
1340
|
+
consumed: z7__namespace.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
1341
|
+
blockNumber: z7__namespace.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
1342
|
+
signature: z7__namespace.string().regex(/^0x[0-9a-fA-F]{130}$/, {
|
|
1343
|
+
message: "Signature must be a valid 65-byte hex string"
|
|
1344
|
+
}).transform(transformHex).optional()
|
|
1345
|
+
});
|
|
1346
|
+
if (!omitHash) base = base.extend({ hash: OfferHashSchema });
|
|
1347
|
+
return base.refine((data) => data.start < data.expiry, {
|
|
1348
|
+
message: "Start must be before expiry",
|
|
1349
|
+
path: ["start"]
|
|
1350
|
+
}).refine((data) => data.expiry <= data.maturity, {
|
|
1351
|
+
message: "Expiry cannot be after maturity",
|
|
1352
|
+
path: ["expiry"]
|
|
1353
|
+
});
|
|
418
1354
|
};
|
|
419
|
-
function
|
|
1355
|
+
function from5(input) {
|
|
420
1356
|
try {
|
|
421
|
-
const parsedOffer =
|
|
422
|
-
const parsedHash =
|
|
1357
|
+
const parsedOffer = OfferSchema({ omitHash: true }).parse(input);
|
|
1358
|
+
const parsedHash = OfferHashSchema.parse(hash(parsedOffer));
|
|
423
1359
|
return {
|
|
424
1360
|
...parsedOffer,
|
|
425
1361
|
hash: parsedHash
|
|
426
1362
|
};
|
|
427
1363
|
} catch (error) {
|
|
428
|
-
throw new
|
|
1364
|
+
throw new InvalidOfferError(error);
|
|
429
1365
|
}
|
|
430
1366
|
}
|
|
431
|
-
function
|
|
432
|
-
return
|
|
1367
|
+
function fromSnakeCase3(input) {
|
|
1368
|
+
return from5(fromSnakeCase(input));
|
|
433
1369
|
}
|
|
434
|
-
function
|
|
435
|
-
return
|
|
1370
|
+
function toSnakeCase2(offer) {
|
|
1371
|
+
return toSnakeCase(offer);
|
|
436
1372
|
}
|
|
437
|
-
function
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
1373
|
+
function random2() {
|
|
1374
|
+
const loanToken = accounts.privateKeyToAccount(accounts.generatePrivateKey()).address;
|
|
1375
|
+
const maturity = from3("end_of_month");
|
|
1376
|
+
const expiry = from3("end_of_week") - 1;
|
|
1377
|
+
const lltv = from(0.965);
|
|
1378
|
+
const offer = from5({
|
|
1379
|
+
offering: accounts.privateKeyToAccount(accounts.generatePrivateKey()).address,
|
|
1380
|
+
assets: BigInt(Math.floor(Math.random() * 1e6)),
|
|
1381
|
+
rate: BigInt(Math.floor(Math.random() * 1e6)),
|
|
1382
|
+
maturity,
|
|
1383
|
+
expiry,
|
|
1384
|
+
start: expiry - 10,
|
|
1385
|
+
nonce: BigInt(Math.floor(Math.random() * 1e6)),
|
|
1386
|
+
buy: Math.random() > 0.5,
|
|
1387
|
+
chainId: 1n,
|
|
1388
|
+
loanToken,
|
|
1389
|
+
collaterals: [
|
|
1390
|
+
from2({
|
|
1391
|
+
asset: viem.zeroAddress,
|
|
1392
|
+
oracle: viem.zeroAddress,
|
|
1393
|
+
lltv
|
|
1394
|
+
})
|
|
1395
|
+
],
|
|
1396
|
+
callback: {
|
|
1397
|
+
address: viem.zeroAddress,
|
|
1398
|
+
data: "0x",
|
|
1399
|
+
gasLimit: 0n
|
|
1400
|
+
},
|
|
1401
|
+
consumed: 0n,
|
|
1402
|
+
blockNumber: Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
|
|
444
1403
|
});
|
|
1404
|
+
return offer;
|
|
445
1405
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
id: `${blockNumber.toString()}-${logIndex.toString()}-${chainId}-${transactionHash}`,
|
|
450
|
-
chainId: BigInt(chainId),
|
|
451
|
-
offering: user,
|
|
452
|
-
nonce,
|
|
453
|
-
amount
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
var InvalidRouterOfferError = class extends mempool.Errors.BaseError {
|
|
457
|
-
constructor(error) {
|
|
458
|
-
super("Invalid router offer.", { cause: error });
|
|
459
|
-
__publicField(this, "name", "RouterOffer.InvalidRouterOfferError");
|
|
460
|
-
}
|
|
461
|
-
};
|
|
462
|
-
|
|
463
|
-
// src/core/router/Client.ts
|
|
464
|
-
var Client_exports = {};
|
|
465
|
-
__export(Client_exports, {
|
|
466
|
-
HttpForbiddenError: () => HttpForbiddenError,
|
|
467
|
-
HttpGetOffersFailedError: () => HttpGetOffersFailedError,
|
|
468
|
-
HttpRateLimitError: () => HttpRateLimitError,
|
|
469
|
-
HttpUnauthorizedError: () => HttpUnauthorizedError,
|
|
470
|
-
InvalidUrlError: () => InvalidUrlError,
|
|
471
|
-
connect: () => connect,
|
|
472
|
-
get: () => get,
|
|
473
|
-
match: () => match
|
|
1406
|
+
var domain = (chainId) => ({
|
|
1407
|
+
chainId,
|
|
1408
|
+
verifyingContract: viem.zeroAddress
|
|
474
1409
|
});
|
|
475
|
-
var
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
max_amount: v4.z.bigint({ coerce: true }).positive({
|
|
525
|
-
message: "Max amount must be a positive number"
|
|
526
|
-
}).optional().meta({
|
|
527
|
-
description: "Maximum amount of assets in the offer",
|
|
528
|
-
example: "10000"
|
|
529
|
-
}),
|
|
530
|
-
// Rate range
|
|
531
|
-
min_rate: v4.z.bigint({ coerce: true }).positive({
|
|
532
|
-
message: "Min rate must be a positive number"
|
|
533
|
-
}).optional().meta({
|
|
534
|
-
description: "Minimum rate per asset (in wei)",
|
|
535
|
-
example: "500000000000000000"
|
|
536
|
-
}),
|
|
537
|
-
max_rate: v4.z.bigint({ coerce: true }).positive({
|
|
538
|
-
message: "Max rate must be a positive number"
|
|
539
|
-
}).optional().meta({
|
|
540
|
-
description: "Maximum rate per asset (in wei)",
|
|
541
|
-
example: "1500000000000000000"
|
|
542
|
-
}),
|
|
543
|
-
// Time range
|
|
544
|
-
min_maturity: v4.z.coerce.number().int().min(0).optional().meta({
|
|
545
|
-
description: "Minimum maturity timestamp (Unix timestamp in seconds)",
|
|
546
|
-
example: "1700000000"
|
|
547
|
-
}),
|
|
548
|
-
max_maturity: v4.z.coerce.number().int().min(0).optional().meta({
|
|
549
|
-
description: "Maximum maturity timestamp (Unix timestamp in seconds)",
|
|
550
|
-
example: "1800000000"
|
|
551
|
-
}),
|
|
552
|
-
min_expiry: v4.z.coerce.number().int().optional().meta({
|
|
553
|
-
description: "Minimum expiry timestamp (Unix timestamp in seconds)",
|
|
554
|
-
example: "1700000000"
|
|
555
|
-
}),
|
|
556
|
-
max_expiry: v4.z.coerce.number().int().optional().meta({
|
|
557
|
-
description: "Maximum expiry timestamp (Unix timestamp in seconds)",
|
|
558
|
-
example: "1800000000"
|
|
559
|
-
}),
|
|
560
|
-
// Collateral filtering
|
|
561
|
-
collateral_assets: v4.z.string().regex(/^0x[a-fA-F0-9]{40}(,0x[a-fA-F0-9]{40})*$/, {
|
|
562
|
-
message: "Collateral assets must be comma-separated Ethereum addresses"
|
|
563
|
-
}).transform((val) => val.split(",").map((addr) => addr.toLowerCase())).optional().meta({
|
|
564
|
-
description: "Filter by multiple collateral assets (comma-separated)",
|
|
565
|
-
example: "0x1234567890123456789012345678901234567890,0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
|
|
566
|
-
}),
|
|
567
|
-
collateral_oracles: v4.z.string().regex(/^0x[a-fA-F0-9]{40}(,0x[a-fA-F0-9]{40})*$/, {
|
|
568
|
-
message: "Collateral oracles must be comma-separated Ethereum addresses"
|
|
569
|
-
}).transform((val) => val.split(",").map((addr) => addr.toLowerCase())).optional().meta({
|
|
570
|
-
description: "Filter by multiple rate oracles (comma-separated)",
|
|
571
|
-
example: "0x1234567890123456789012345678901234567890,0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
|
|
572
|
-
}),
|
|
573
|
-
collateral_tuple: v4.z.string().transform((val, ctx) => {
|
|
574
|
-
const pattern = /^(0x[a-fA-F0-9]{40}(:0x[a-fA-F0-9]{40})?(:[0-9]+(\.[0-9]+)?)?)(#0x[a-fA-F0-9]{40}(:0x[a-fA-F0-9]{40})?(:[0-9]+(\.[0-9]+)?)?)*$/;
|
|
575
|
-
if (!pattern.test(val)) {
|
|
576
|
-
ctx.addIssue({
|
|
577
|
-
code: "custom",
|
|
578
|
-
message: "collateral_tuple has an invalid format",
|
|
579
|
-
input: val
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
return val.split("#").map((tuple) => {
|
|
583
|
-
const parts = tuple.split(":");
|
|
584
|
-
if (parts.length === 0 || !parts[0]) {
|
|
585
|
-
ctx.addIssue({
|
|
586
|
-
code: "custom",
|
|
587
|
-
message: "Asset address is required for each collateral tuple",
|
|
588
|
-
path: ["asset"],
|
|
589
|
-
input: val
|
|
590
|
-
});
|
|
591
|
-
return v4.z.NEVER;
|
|
592
|
-
}
|
|
593
|
-
const asset = parts[0]?.toLowerCase();
|
|
594
|
-
const oracle = parts[1]?.toLowerCase();
|
|
595
|
-
const lltv = parts[2] ? parseFloat(parts[2]) : void 0;
|
|
596
|
-
if (lltv !== void 0 && (lltv < MIN_LLTV || lltv > MAX_LLTV)) {
|
|
597
|
-
ctx.addIssue({
|
|
598
|
-
code: "custom",
|
|
599
|
-
message: `LLTV must be between ${MIN_LLTV} and ${MAX_LLTV} (0-100%)`,
|
|
600
|
-
path: ["lltv"],
|
|
601
|
-
input: val
|
|
602
|
-
});
|
|
603
|
-
return v4.z.NEVER;
|
|
604
|
-
}
|
|
605
|
-
let lltvValue;
|
|
606
|
-
if (lltv !== void 0) {
|
|
607
|
-
try {
|
|
608
|
-
lltvValue = mempool.LLTV.from(viem.parseUnits(lltv.toString(), 16));
|
|
609
|
-
} catch (e) {
|
|
610
|
-
ctx.issues.push({
|
|
611
|
-
code: "custom",
|
|
612
|
-
message: e instanceof mempool.LLTV.InvalidLLTVError || e instanceof mempool.LLTV.InvalidOptionError ? e.message : "Invalid LLTV.",
|
|
613
|
-
input: lltv,
|
|
614
|
-
path: ["lltv"]
|
|
615
|
-
});
|
|
616
|
-
return v4.z.NEVER;
|
|
617
|
-
}
|
|
1410
|
+
var types = {
|
|
1411
|
+
EIP712Domain: [
|
|
1412
|
+
{ name: "chainId", type: "uint256" },
|
|
1413
|
+
{ name: "verifyingContract", type: "address" }
|
|
1414
|
+
],
|
|
1415
|
+
Offer: [
|
|
1416
|
+
{ name: "offering", type: "address" },
|
|
1417
|
+
{ name: "assets", type: "uint256" },
|
|
1418
|
+
{ name: "rate", type: "uint256" },
|
|
1419
|
+
{ name: "maturity", type: "uint256" },
|
|
1420
|
+
{ name: "expiry", type: "uint256" },
|
|
1421
|
+
{ name: "nonce", type: "uint256" },
|
|
1422
|
+
{ name: "buy", type: "bool" },
|
|
1423
|
+
{ name: "loanToken", type: "address" },
|
|
1424
|
+
{ name: "collaterals", type: "Collateral[]" },
|
|
1425
|
+
{ name: "callback", type: "Callback" }
|
|
1426
|
+
],
|
|
1427
|
+
Collateral: [
|
|
1428
|
+
{ name: "asset", type: "address" },
|
|
1429
|
+
{ name: "oracle", type: "address" },
|
|
1430
|
+
{ name: "lltv", type: "uint256" }
|
|
1431
|
+
],
|
|
1432
|
+
Callback: [
|
|
1433
|
+
{ name: "address", type: "address" },
|
|
1434
|
+
{ name: "data", type: "bytes" },
|
|
1435
|
+
{ name: "gasLimit", type: "uint256" }
|
|
1436
|
+
]
|
|
1437
|
+
};
|
|
1438
|
+
function sign(offer, wallet) {
|
|
1439
|
+
if (!wallet.account) throw new AccountNotSetError();
|
|
1440
|
+
return wallet.signTypedData({
|
|
1441
|
+
account: wallet.account,
|
|
1442
|
+
domain: domain(offer.chainId),
|
|
1443
|
+
types,
|
|
1444
|
+
primaryType: "Offer",
|
|
1445
|
+
message: {
|
|
1446
|
+
offering: offer.offering.toLowerCase(),
|
|
1447
|
+
assets: offer.assets,
|
|
1448
|
+
rate: offer.rate,
|
|
1449
|
+
maturity: BigInt(offer.maturity),
|
|
1450
|
+
expiry: BigInt(offer.expiry),
|
|
1451
|
+
nonce: offer.nonce,
|
|
1452
|
+
buy: offer.buy,
|
|
1453
|
+
loanToken: offer.loanToken.toLowerCase(),
|
|
1454
|
+
collaterals: offer.collaterals,
|
|
1455
|
+
callback: {
|
|
1456
|
+
address: offer.callback.address.toLowerCase(),
|
|
1457
|
+
data: offer.callback.data,
|
|
1458
|
+
gasLimit: offer.callback.gasLimit
|
|
618
1459
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
description: "Field to sort results by",
|
|
640
|
-
example: "rate"
|
|
641
|
-
}),
|
|
642
|
-
sort_order: v4.z.enum(["asc", "desc"]).optional().default("desc").meta({
|
|
643
|
-
description: "Sort direction: asc (ascending) or desc (descending, default)",
|
|
644
|
-
example: "desc"
|
|
645
|
-
}),
|
|
646
|
-
// Pagination
|
|
647
|
-
cursor: v4.z.string().optional().refine(
|
|
648
|
-
(val) => {
|
|
649
|
-
if (!val) return true;
|
|
650
|
-
try {
|
|
651
|
-
const decoded = decode2(val);
|
|
652
|
-
return decoded !== null;
|
|
653
|
-
} catch (_error) {
|
|
654
|
-
return false;
|
|
1460
|
+
}
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
function hash(offer) {
|
|
1464
|
+
return viem.hashTypedData({
|
|
1465
|
+
domain: domain(offer.chainId),
|
|
1466
|
+
message: {
|
|
1467
|
+
offering: offer.offering.toLowerCase(),
|
|
1468
|
+
assets: offer.assets,
|
|
1469
|
+
rate: offer.rate,
|
|
1470
|
+
maturity: BigInt(offer.maturity),
|
|
1471
|
+
expiry: BigInt(offer.expiry),
|
|
1472
|
+
nonce: offer.nonce,
|
|
1473
|
+
buy: offer.buy,
|
|
1474
|
+
loanToken: offer.loanToken.toLowerCase(),
|
|
1475
|
+
collaterals: offer.collaterals,
|
|
1476
|
+
callback: {
|
|
1477
|
+
address: offer.callback.address.toLowerCase(),
|
|
1478
|
+
data: offer.callback.data,
|
|
1479
|
+
gasLimit: offer.callback.gasLimit
|
|
655
1480
|
}
|
|
656
1481
|
},
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
message: `Limit cannot exceed ${MAX_LIMIT}`
|
|
1482
|
+
primaryType: "Offer",
|
|
1483
|
+
types
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
function obligationId(offer) {
|
|
1487
|
+
return id(
|
|
1488
|
+
from4({
|
|
1489
|
+
chainId: offer.chainId,
|
|
1490
|
+
loanToken: offer.loanToken,
|
|
1491
|
+
collaterals: offer.collaterals,
|
|
1492
|
+
maturity: offer.maturity
|
|
669
1493
|
})
|
|
670
|
-
)
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
{
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
{
|
|
683
|
-
message: "max_expiry must be greater than or equal to min_expiry",
|
|
684
|
-
path: ["max_expiry"]
|
|
685
|
-
}
|
|
686
|
-
).refine(
|
|
687
|
-
(data) => data.min_amount === void 0 || data.max_amount === void 0 || data.max_amount >= data.min_amount,
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
var OfferAbi = [
|
|
1497
|
+
{ name: "offering", type: "address" },
|
|
1498
|
+
{ name: "assets", type: "uint256" },
|
|
1499
|
+
{ name: "rate", type: "uint256" },
|
|
1500
|
+
{ name: "maturity", type: "uint256" },
|
|
1501
|
+
{ name: "expiry", type: "uint256" },
|
|
1502
|
+
{ name: "nonce", type: "uint256" },
|
|
1503
|
+
{ name: "buy", type: "bool" },
|
|
1504
|
+
{ name: "chainId", type: "uint256" },
|
|
1505
|
+
{ name: "loanToken", type: "address" },
|
|
1506
|
+
{ name: "start", type: "uint256" },
|
|
688
1507
|
{
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
1508
|
+
name: "collaterals",
|
|
1509
|
+
type: "tuple[]",
|
|
1510
|
+
components: [
|
|
1511
|
+
{ name: "asset", type: "address" },
|
|
1512
|
+
{ name: "oracle", type: "address" },
|
|
1513
|
+
{ name: "lltv", type: "uint256" }
|
|
1514
|
+
]
|
|
1515
|
+
},
|
|
694
1516
|
{
|
|
695
|
-
|
|
696
|
-
|
|
1517
|
+
name: "callback",
|
|
1518
|
+
type: "tuple",
|
|
1519
|
+
components: [
|
|
1520
|
+
{ name: "address", type: "address" },
|
|
1521
|
+
{ name: "data", type: "bytes" },
|
|
1522
|
+
{ name: "gasLimit", type: "uint256" }
|
|
1523
|
+
]
|
|
1524
|
+
},
|
|
1525
|
+
{ name: "signature", type: "bytes" }
|
|
1526
|
+
];
|
|
1527
|
+
function encode2(offer) {
|
|
1528
|
+
return viem.encodeAbiParameters(OfferAbi, [
|
|
1529
|
+
offer.offering,
|
|
1530
|
+
offer.assets,
|
|
1531
|
+
offer.rate,
|
|
1532
|
+
BigInt(offer.maturity),
|
|
1533
|
+
BigInt(offer.expiry),
|
|
1534
|
+
offer.nonce,
|
|
1535
|
+
offer.buy,
|
|
1536
|
+
offer.chainId,
|
|
1537
|
+
offer.loanToken,
|
|
1538
|
+
BigInt(offer.start),
|
|
1539
|
+
offer.collaterals,
|
|
1540
|
+
offer.callback,
|
|
1541
|
+
offer.signature ?? "0x"
|
|
1542
|
+
]);
|
|
1543
|
+
}
|
|
1544
|
+
function decode2(data, blockNumber) {
|
|
1545
|
+
let decoded;
|
|
1546
|
+
try {
|
|
1547
|
+
decoded = viem.decodeAbiParameters(OfferAbi, data);
|
|
1548
|
+
} catch (error) {
|
|
1549
|
+
throw new InvalidOfferError(error);
|
|
1550
|
+
}
|
|
1551
|
+
const offer = from5({
|
|
1552
|
+
offering: decoded[0],
|
|
1553
|
+
assets: decoded[1],
|
|
1554
|
+
rate: decoded[2],
|
|
1555
|
+
maturity: from3(Number(decoded[3])),
|
|
1556
|
+
expiry: Number(decoded[4]),
|
|
1557
|
+
nonce: decoded[5],
|
|
1558
|
+
buy: decoded[6],
|
|
1559
|
+
chainId: decoded[7],
|
|
1560
|
+
loanToken: decoded[8],
|
|
1561
|
+
start: Number(decoded[9]),
|
|
1562
|
+
collaterals: decoded[10].map((c) => {
|
|
1563
|
+
return from2({
|
|
1564
|
+
asset: c.asset,
|
|
1565
|
+
oracle: c.oracle,
|
|
1566
|
+
lltv: c.lltv
|
|
1567
|
+
});
|
|
1568
|
+
}),
|
|
1569
|
+
callback: {
|
|
1570
|
+
address: decoded[11].address,
|
|
1571
|
+
data: decoded[11].data,
|
|
1572
|
+
gasLimit: decoded[11].gasLimit
|
|
1573
|
+
},
|
|
1574
|
+
consumed: 0n,
|
|
1575
|
+
blockNumber: Number(blockNumber),
|
|
1576
|
+
...decoded[12] === "0x" ? {} : { signature: decoded[12] }
|
|
1577
|
+
});
|
|
1578
|
+
return offer;
|
|
1579
|
+
}
|
|
1580
|
+
var consumedEvent = {
|
|
1581
|
+
type: "event",
|
|
1582
|
+
name: "Consumed",
|
|
1583
|
+
inputs: [
|
|
1584
|
+
{ name: "user", type: "address", indexed: true, internalType: "address" },
|
|
1585
|
+
{ name: "nonce", type: "uint256", indexed: true, internalType: "uint256" },
|
|
1586
|
+
{ name: "amount", type: "uint256", indexed: false, internalType: "uint256" }
|
|
1587
|
+
],
|
|
1588
|
+
anonymous: false
|
|
1589
|
+
};
|
|
1590
|
+
function fromConsumedLog(parameters) {
|
|
1591
|
+
const { blockNumber, logIndex, chainId, transactionHash, user, nonce, amount } = parameters;
|
|
1592
|
+
return {
|
|
1593
|
+
id: `${blockNumber.toString()}-${logIndex.toString()}-${chainId}-${transactionHash}`,
|
|
1594
|
+
chainId: BigInt(chainId),
|
|
1595
|
+
offering: user,
|
|
1596
|
+
nonce,
|
|
1597
|
+
amount,
|
|
1598
|
+
blockNumber: Number(blockNumber)
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1601
|
+
var InvalidOfferError = class extends BaseError {
|
|
1602
|
+
constructor(error) {
|
|
1603
|
+
super("Invalid offer.", { cause: error });
|
|
1604
|
+
__publicField(this, "name", "Offer.InvalidOfferError");
|
|
697
1605
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
{
|
|
701
|
-
|
|
702
|
-
|
|
1606
|
+
};
|
|
1607
|
+
var AccountNotSetError = class extends BaseError {
|
|
1608
|
+
constructor() {
|
|
1609
|
+
super("Account not set.");
|
|
1610
|
+
__publicField(this, "name", "Offer.AccountNotSetError");
|
|
703
1611
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
return Number.parseInt(val, 10);
|
|
727
|
-
}).pipe(v4.z.number().positive()).meta({
|
|
728
|
-
description: "The blockchain network chain ID",
|
|
729
|
-
example: "1"
|
|
730
|
-
}),
|
|
731
|
-
// Optional parameters
|
|
732
|
-
rate: v4.z.bigint({ coerce: true }).positive({
|
|
733
|
-
message: "Rate must be a positive number"
|
|
734
|
-
}).optional().meta({
|
|
735
|
-
description: "Rate per asset (in wei) for matching offers",
|
|
736
|
-
example: "1000000000000000000"
|
|
737
|
-
}),
|
|
738
|
-
// Collateral filtering
|
|
739
|
-
collaterals: v4.z.string().transform((val, ctx) => {
|
|
740
|
-
const pattern = /^(0x[a-fA-F0-9]{40}:0x[a-fA-F0-9]{40}:[0-9]+(\.[0-9]+)?)(#0x[a-fA-F0-9]{40}:0x[a-fA-F0-9]{40}:[0-9]+(\.[0-9]+)?)*$/;
|
|
741
|
-
if (!pattern.test(val)) {
|
|
742
|
-
ctx.addIssue({
|
|
743
|
-
code: "custom",
|
|
744
|
-
message: "Collaterals must be in format: asset:oracle:lltv#asset2:oracle2:lltv2. All fields are required for each collateral.",
|
|
745
|
-
input: val
|
|
746
|
-
});
|
|
747
|
-
}
|
|
748
|
-
return val.split("#").map((collateral) => {
|
|
749
|
-
const parts = collateral.split(":");
|
|
750
|
-
if (parts.length !== 3) {
|
|
751
|
-
ctx.addIssue({
|
|
752
|
-
code: "custom",
|
|
753
|
-
message: "Each collateral must have exactly 3 parts: asset:oracle:lltv",
|
|
754
|
-
path: ["collaterals"],
|
|
755
|
-
input: val
|
|
756
|
-
});
|
|
757
|
-
return v4.z.NEVER;
|
|
758
|
-
}
|
|
759
|
-
const [asset, oracle, lltvStr] = parts;
|
|
760
|
-
if (!asset || !oracle || !lltvStr) {
|
|
761
|
-
ctx.addIssue({
|
|
762
|
-
code: "custom",
|
|
763
|
-
message: "Asset, oracle, and lltv are all required for each collateral",
|
|
764
|
-
path: ["collaterals"],
|
|
765
|
-
input: val
|
|
766
|
-
});
|
|
767
|
-
}
|
|
768
|
-
let lltvValue;
|
|
769
|
-
if (lltvStr !== void 0) {
|
|
770
|
-
try {
|
|
771
|
-
lltvValue = mempool.LLTV.from(viem.parseUnits(lltvStr, 16));
|
|
772
|
-
} catch (e) {
|
|
773
|
-
ctx.issues.push({
|
|
774
|
-
code: "custom",
|
|
775
|
-
message: e instanceof mempool.LLTV.InvalidLLTVError || e instanceof mempool.LLTV.InvalidOptionError ? e.message : "Invalid LLTV.",
|
|
776
|
-
input: lltvStr,
|
|
777
|
-
path: ["lltv"]
|
|
778
|
-
});
|
|
779
|
-
return v4.z.NEVER;
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
return {
|
|
783
|
-
asset: asset.toLowerCase(),
|
|
784
|
-
oracle: oracle.toLowerCase(),
|
|
785
|
-
lltv: lltvValue
|
|
786
|
-
};
|
|
787
|
-
});
|
|
788
|
-
}).optional().meta({
|
|
789
|
-
description: "Collateral requirements in format: asset:oracle:lltv#asset2:oracle2:lltv2. Use # to separate multiple collaterals.",
|
|
790
|
-
example: "0x1234567890123456789012345678901234567890:0xabcdefabcdefabcdefabcdefabcdefabcdefabcd:86#0x9876543210987654321098765432109876543210:0xfedcbafedcbafedcbafedcbafedcbafedcbafedc:94.5"
|
|
791
|
-
}),
|
|
792
|
-
// Maturity filtering
|
|
793
|
-
maturity: v4.z.coerce.number().int().min(0).optional().meta({
|
|
794
|
-
description: "Maturity timestamp (Unix timestamp in seconds)",
|
|
795
|
-
example: "1700000000"
|
|
796
|
-
}),
|
|
797
|
-
min_maturity: v4.z.coerce.number().int().min(0).optional().meta({
|
|
798
|
-
description: "Minimum maturity timestamp (Unix timestamp in seconds)",
|
|
799
|
-
example: "1700000000"
|
|
800
|
-
}),
|
|
801
|
-
max_maturity: v4.z.coerce.number().int().min(0).optional().meta({
|
|
802
|
-
description: "Maximum maturity timestamp (Unix timestamp in seconds)",
|
|
803
|
-
example: "1800000000"
|
|
804
|
-
}),
|
|
805
|
-
// Asset and creator filtering
|
|
806
|
-
loan_token: v4.z.string().regex(/^0x[a-fA-F0-9]{40}$/, {
|
|
807
|
-
message: "Loan asset must be a valid Ethereum address"
|
|
808
|
-
}).transform((val) => val.toLowerCase()).optional().meta({
|
|
809
|
-
description: "The loan asset address to match against",
|
|
810
|
-
example: "0x1234567890123456789012345678901234567890"
|
|
811
|
-
}),
|
|
812
|
-
creator: v4.z.string().regex(/^0x[a-fA-F0-9]{40}$/, {
|
|
813
|
-
message: "Creator must be a valid Ethereum address"
|
|
814
|
-
}).transform((val) => val.toLowerCase()).optional().meta({
|
|
815
|
-
description: "Filter by a specific offer creator address",
|
|
816
|
-
example: "0x1234567890123456789012345678901234567890"
|
|
817
|
-
}),
|
|
818
|
-
// Pagination
|
|
819
|
-
cursor: v4.z.string().optional().refine(
|
|
1612
|
+
};
|
|
1613
|
+
|
|
1614
|
+
// src/core/types.ts
|
|
1615
|
+
var BrandTypeId = Symbol.for("mempool/Brand");
|
|
1616
|
+
|
|
1617
|
+
// src/api/Api/Schema/ObligationResponse.ts
|
|
1618
|
+
function from6(obligation) {
|
|
1619
|
+
return toSnakeCase({ id: Obligation_exports.id(obligation), ...obligation });
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
// src/api/Api/Schema/OfferResponse.ts
|
|
1623
|
+
var OfferResponse_exports = {};
|
|
1624
|
+
__export(OfferResponse_exports, {
|
|
1625
|
+
from: () => from7
|
|
1626
|
+
});
|
|
1627
|
+
function from7(offer) {
|
|
1628
|
+
return toSnakeCase(offer);
|
|
1629
|
+
}
|
|
1630
|
+
var MAX_LIMIT = 100;
|
|
1631
|
+
var DEFAULT_LIMIT = 20;
|
|
1632
|
+
var PaginationQueryParams = z7__namespace.object({
|
|
1633
|
+
cursor: z7__namespace.string().optional().refine(
|
|
820
1634
|
(val) => {
|
|
821
1635
|
if (!val) return true;
|
|
822
1636
|
try {
|
|
823
|
-
const decoded =
|
|
1637
|
+
const decoded = Cursor_exports.decode(val);
|
|
824
1638
|
return decoded !== null;
|
|
825
1639
|
} catch (_error) {
|
|
826
1640
|
return false;
|
|
@@ -833,34 +1647,49 @@ var MatchOffersQueryParams = v4.z.object({
|
|
|
833
1647
|
description: "Pagination cursor in base64url-encoded format",
|
|
834
1648
|
example: "eyJzb3J0IjoicHJpY2UiLCJkaXIiOiJkZXNjIiwicHJpY2UiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwiaGFzaCI6IjB4ZGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIifQ"
|
|
835
1649
|
}),
|
|
836
|
-
limit:
|
|
1650
|
+
limit: z7__namespace.string().regex(/^[1-9]\d*$/, {
|
|
837
1651
|
message: "Limit must be a positive integer"
|
|
838
1652
|
}).transform((val) => Number.parseInt(val, 10)).pipe(
|
|
839
|
-
|
|
1653
|
+
z7__namespace.number().max(MAX_LIMIT, {
|
|
840
1654
|
message: `Limit cannot exceed ${MAX_LIMIT}`
|
|
841
1655
|
})
|
|
842
1656
|
).optional().default(DEFAULT_LIMIT).meta({
|
|
843
1657
|
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
|
|
844
1658
|
example: 10
|
|
845
1659
|
})
|
|
846
|
-
})
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
)
|
|
1660
|
+
});
|
|
1661
|
+
var GetOffersQueryParams = z7__namespace.object({
|
|
1662
|
+
...PaginationQueryParams.shape,
|
|
1663
|
+
side: z7__namespace.enum(["buy", "sell"]).meta({
|
|
1664
|
+
description: "Side of the offer.",
|
|
1665
|
+
example: "buy"
|
|
1666
|
+
}),
|
|
1667
|
+
obligation_id: z7__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({
|
|
1668
|
+
description: "Offers obligation id",
|
|
1669
|
+
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
1670
|
+
})
|
|
1671
|
+
});
|
|
1672
|
+
var GetObligationsQueryParams = z7__namespace.object({
|
|
1673
|
+
...PaginationQueryParams.shape,
|
|
1674
|
+
cursor: z7__namespace.string().optional().meta({
|
|
1675
|
+
description: "Obligation id cursor",
|
|
1676
|
+
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
1677
|
+
})
|
|
1678
|
+
});
|
|
853
1679
|
var schemas = {
|
|
854
1680
|
get_offers: GetOffersQueryParams,
|
|
855
|
-
|
|
1681
|
+
get_obligations: GetObligationsQueryParams
|
|
856
1682
|
};
|
|
1683
|
+
function parse(action, query) {
|
|
1684
|
+
return schemas[action].parse(query);
|
|
1685
|
+
}
|
|
857
1686
|
function safeParse(action, query, error) {
|
|
858
1687
|
return schemas[action].safeParse(query, {
|
|
859
1688
|
error
|
|
860
1689
|
});
|
|
861
1690
|
}
|
|
862
1691
|
|
|
863
|
-
// src/
|
|
1692
|
+
// src/api/Api/Schema/openapi.ts
|
|
864
1693
|
var successResponseSchema = v4.z.object({
|
|
865
1694
|
status: v4.z.literal("success"),
|
|
866
1695
|
cursor: v4.z.string().nullable(),
|
|
@@ -883,8 +1712,8 @@ var errorResponseSchema = v4.z.object({
|
|
|
883
1712
|
var paths = {
|
|
884
1713
|
"/v1/offers": {
|
|
885
1714
|
get: {
|
|
886
|
-
summary: "
|
|
887
|
-
description: "
|
|
1715
|
+
summary: "Offers",
|
|
1716
|
+
description: "Find offers that match specific criteria",
|
|
888
1717
|
tags: ["Offers"],
|
|
889
1718
|
requestParams: {
|
|
890
1719
|
query: GetOffersQueryParams
|
|
@@ -909,13 +1738,13 @@ var paths = {
|
|
|
909
1738
|
}
|
|
910
1739
|
}
|
|
911
1740
|
},
|
|
912
|
-
"/v1/
|
|
1741
|
+
"/v1/obligations": {
|
|
913
1742
|
get: {
|
|
914
|
-
summary: "
|
|
915
|
-
description: "
|
|
916
|
-
tags: ["
|
|
1743
|
+
summary: "Obligations",
|
|
1744
|
+
description: "List obligations with pagination support",
|
|
1745
|
+
tags: ["Obligations"],
|
|
917
1746
|
requestParams: {
|
|
918
|
-
query:
|
|
1747
|
+
query: GetObligationsQueryParams
|
|
919
1748
|
},
|
|
920
1749
|
responses: {
|
|
921
1750
|
200: {
|
|
@@ -936,9 +1765,60 @@ var paths = {
|
|
|
936
1765
|
}
|
|
937
1766
|
}
|
|
938
1767
|
}
|
|
1768
|
+
},
|
|
1769
|
+
"/v1/health": {
|
|
1770
|
+
get: {
|
|
1771
|
+
summary: "Router status",
|
|
1772
|
+
description: "Retrieve the aggregated status of the router.",
|
|
1773
|
+
tags: ["Health"],
|
|
1774
|
+
responses: {
|
|
1775
|
+
200: {
|
|
1776
|
+
description: "Success",
|
|
1777
|
+
content: {
|
|
1778
|
+
"application/json": {
|
|
1779
|
+
schema: RouterStatusResponse
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
},
|
|
1786
|
+
"/v1/health/collectors": {
|
|
1787
|
+
get: {
|
|
1788
|
+
summary: "Collectors health",
|
|
1789
|
+
description: "Retrieve the block numbers processed by collectors and their sync status.",
|
|
1790
|
+
tags: ["Health"],
|
|
1791
|
+
responses: {
|
|
1792
|
+
200: {
|
|
1793
|
+
description: "Success",
|
|
1794
|
+
content: {
|
|
1795
|
+
"application/json": {
|
|
1796
|
+
schema: CollectorsHealthResponse
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
},
|
|
1803
|
+
"/v1/health/chains": {
|
|
1804
|
+
get: {
|
|
1805
|
+
summary: "Chains health",
|
|
1806
|
+
description: "Retrieve the latest block processed for each chain.",
|
|
1807
|
+
tags: ["Health"],
|
|
1808
|
+
responses: {
|
|
1809
|
+
200: {
|
|
1810
|
+
description: "Success",
|
|
1811
|
+
content: {
|
|
1812
|
+
"application/json": {
|
|
1813
|
+
schema: ChainsHealthResponse
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
939
1819
|
}
|
|
940
1820
|
};
|
|
941
|
-
zodOpenapi.createDocument({
|
|
1821
|
+
var OpenApi = zodOpenapi.createDocument({
|
|
942
1822
|
openapi: "3.1.0",
|
|
943
1823
|
info: {
|
|
944
1824
|
title: "Router API",
|
|
@@ -948,6 +1828,12 @@ zodOpenapi.createDocument({
|
|
|
948
1828
|
tags: [
|
|
949
1829
|
{
|
|
950
1830
|
name: "Offers"
|
|
1831
|
+
},
|
|
1832
|
+
{
|
|
1833
|
+
name: "Obligations"
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
name: "Health"
|
|
951
1837
|
}
|
|
952
1838
|
],
|
|
953
1839
|
servers: [
|
|
@@ -963,120 +1849,40 @@ zodOpenapi.createDocument({
|
|
|
963
1849
|
paths
|
|
964
1850
|
});
|
|
965
1851
|
|
|
966
|
-
// src/
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
consumed,
|
|
981
|
-
status,
|
|
982
|
-
metadata
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
// src/core/router/Client.ts
|
|
987
|
-
function connect(opts) {
|
|
988
|
-
const u = new URL(opts?.url || "https://router.morpho.dev");
|
|
1852
|
+
// src/api/Client.ts
|
|
1853
|
+
var Client_exports = {};
|
|
1854
|
+
__export(Client_exports, {
|
|
1855
|
+
HttpForbiddenError: () => HttpForbiddenError,
|
|
1856
|
+
HttpGetApiFailedError: () => HttpGetApiFailedError,
|
|
1857
|
+
HttpRateLimitError: () => HttpRateLimitError,
|
|
1858
|
+
HttpUnauthorizedError: () => HttpUnauthorizedError,
|
|
1859
|
+
InvalidUrlError: () => InvalidUrlError,
|
|
1860
|
+
connect: () => connect,
|
|
1861
|
+
getObligations: () => getObligations,
|
|
1862
|
+
getOffers: () => getOffers
|
|
1863
|
+
});
|
|
1864
|
+
function connect(options) {
|
|
1865
|
+
const u = new URL(options?.url || "https://router.morpho.dev");
|
|
989
1866
|
if (u.protocol !== "http:" && u.protocol !== "https:") {
|
|
990
1867
|
throw new InvalidUrlError(u.toString());
|
|
991
1868
|
}
|
|
992
|
-
const headers =
|
|
1869
|
+
const headers = options?.headers ?? new Headers();
|
|
993
1870
|
headers.set("Content-Type", "application/json");
|
|
994
|
-
|
|
1871
|
+
options?.apiKey !== void 0 ? headers.set("X-API-Key", options.apiKey) : null;
|
|
995
1872
|
const config = {
|
|
996
1873
|
url: u,
|
|
997
1874
|
headers
|
|
998
1875
|
};
|
|
999
1876
|
return {
|
|
1000
1877
|
...config,
|
|
1001
|
-
|
|
1002
|
-
|
|
1878
|
+
getOffers: (parameters) => getOffers(config, parameters),
|
|
1879
|
+
getObligations: (parameters) => getObligations(config, parameters)
|
|
1003
1880
|
};
|
|
1004
1881
|
}
|
|
1005
|
-
async function
|
|
1882
|
+
async function getOffers(config, parameters) {
|
|
1006
1883
|
const url = new URL(`${config.url.toString()}v1/offers`);
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
}
|
|
1010
|
-
if (parameters.side) {
|
|
1011
|
-
url.searchParams.set("side", parameters.side);
|
|
1012
|
-
}
|
|
1013
|
-
if (parameters.chains?.length) {
|
|
1014
|
-
url.searchParams.set("chains", parameters.chains.join(","));
|
|
1015
|
-
}
|
|
1016
|
-
if (parameters.loanTokens?.length) {
|
|
1017
|
-
url.searchParams.set("loan_tokens", parameters.loanTokens.join(","));
|
|
1018
|
-
}
|
|
1019
|
-
if (parameters.status?.length) {
|
|
1020
|
-
url.searchParams.set("status", parameters.status.join(","));
|
|
1021
|
-
}
|
|
1022
|
-
if (parameters.callbackAddresses?.length) {
|
|
1023
|
-
url.searchParams.set("callback_addresses", parameters.callbackAddresses.join(","));
|
|
1024
|
-
}
|
|
1025
|
-
if (parameters.minAmount !== void 0) {
|
|
1026
|
-
url.searchParams.set("min_amount", parameters.minAmount.toString());
|
|
1027
|
-
}
|
|
1028
|
-
if (parameters.maxAmount !== void 0) {
|
|
1029
|
-
url.searchParams.set("max_amount", parameters.maxAmount.toString());
|
|
1030
|
-
}
|
|
1031
|
-
if (parameters.minRate !== void 0) {
|
|
1032
|
-
url.searchParams.set("min_rate", parameters.minRate.toString());
|
|
1033
|
-
}
|
|
1034
|
-
if (parameters.maxRate !== void 0) {
|
|
1035
|
-
url.searchParams.set("max_rate", parameters.maxRate.toString());
|
|
1036
|
-
}
|
|
1037
|
-
if (parameters.minMaturity !== void 0) {
|
|
1038
|
-
url.searchParams.set("min_maturity", parameters.minMaturity.toString());
|
|
1039
|
-
}
|
|
1040
|
-
if (parameters.maxMaturity !== void 0) {
|
|
1041
|
-
url.searchParams.set("max_maturity", parameters.maxMaturity.toString());
|
|
1042
|
-
}
|
|
1043
|
-
if (parameters.minExpiry !== void 0) {
|
|
1044
|
-
url.searchParams.set("min_expiry", parameters.minExpiry.toString());
|
|
1045
|
-
}
|
|
1046
|
-
if (parameters.maxExpiry !== void 0) {
|
|
1047
|
-
url.searchParams.set("max_expiry", parameters.maxExpiry.toString());
|
|
1048
|
-
}
|
|
1049
|
-
if (parameters.collateralAssets?.length) {
|
|
1050
|
-
url.searchParams.set("collateral_assets", parameters.collateralAssets.join(","));
|
|
1051
|
-
}
|
|
1052
|
-
if (parameters.collateralOracles?.length) {
|
|
1053
|
-
url.searchParams.set("collateral_oracles", parameters.collateralOracles.join(","));
|
|
1054
|
-
}
|
|
1055
|
-
if (parameters.collateralTuple?.length) {
|
|
1056
|
-
const tupleStr = parameters.collateralTuple.map(({ asset, oracle, lltv }) => {
|
|
1057
|
-
let result = asset;
|
|
1058
|
-
if (oracle) {
|
|
1059
|
-
result += `:${oracle}`;
|
|
1060
|
-
} else if (lltv !== void 0) {
|
|
1061
|
-
result += `:`;
|
|
1062
|
-
}
|
|
1063
|
-
if (lltv !== void 0) result += `:${viem.formatUnits(lltv, 16)}`;
|
|
1064
|
-
return result;
|
|
1065
|
-
}).join("#");
|
|
1066
|
-
url.searchParams.set("collateral_tuple", tupleStr);
|
|
1067
|
-
}
|
|
1068
|
-
if (parameters.minLltv !== void 0) {
|
|
1069
|
-
url.searchParams.set("min_lltv", viem.formatUnits(parameters.minLltv, 16));
|
|
1070
|
-
}
|
|
1071
|
-
if (parameters.maxLltv !== void 0) {
|
|
1072
|
-
url.searchParams.set("max_lltv", viem.formatUnits(parameters.maxLltv, 16));
|
|
1073
|
-
}
|
|
1074
|
-
if (parameters.sortBy) {
|
|
1075
|
-
url.searchParams.set("sort_by", parameters.sortBy);
|
|
1076
|
-
}
|
|
1077
|
-
if (parameters.sortOrder) {
|
|
1078
|
-
url.searchParams.set("sort_order", parameters.sortOrder);
|
|
1079
|
-
}
|
|
1884
|
+
url.searchParams.set("side", parameters.side);
|
|
1885
|
+
url.searchParams.set("obligation_id", parameters.obligationId.toString());
|
|
1080
1886
|
if (parameters.cursor) {
|
|
1081
1887
|
url.searchParams.set("cursor", parameters.cursor);
|
|
1082
1888
|
}
|
|
@@ -1084,72 +1890,45 @@ async function get(config, parameters) {
|
|
|
1084
1890
|
url.searchParams.set("limit", parameters.limit.toString());
|
|
1085
1891
|
}
|
|
1086
1892
|
const { cursor: returnedCursor, data: offers } = await getApi(config, url);
|
|
1087
|
-
const routerOffers = offers.map(
|
|
1893
|
+
const routerOffers = offers.map(Offer_exports.fromSnakeCase);
|
|
1088
1894
|
return {
|
|
1089
1895
|
cursor: returnedCursor,
|
|
1090
|
-
offers: routerOffers
|
|
1896
|
+
offers: routerOffers
|
|
1091
1897
|
};
|
|
1092
1898
|
}
|
|
1093
|
-
async function
|
|
1094
|
-
const url = new URL(`${config.url.toString()}v1/
|
|
1095
|
-
|
|
1096
|
-
url.searchParams.set("chain_id", parameters.chainId.toString());
|
|
1097
|
-
if (parameters.rate !== void 0) {
|
|
1098
|
-
url.searchParams.set("rate", parameters.rate.toString());
|
|
1099
|
-
}
|
|
1100
|
-
if (parameters.collaterals?.length) {
|
|
1101
|
-
const collateralsStr = parameters.collaterals.map(({ asset, oracle, lltv }) => `${asset}:${oracle}:${viem.formatUnits(lltv, 16)}`).join("#");
|
|
1102
|
-
url.searchParams.set("collaterals", collateralsStr);
|
|
1103
|
-
}
|
|
1104
|
-
if (parameters.maturity !== void 0) {
|
|
1105
|
-
url.searchParams.set("maturity", parameters.maturity.toString());
|
|
1106
|
-
}
|
|
1107
|
-
if (parameters.minMaturity !== void 0) {
|
|
1108
|
-
url.searchParams.set("min_maturity", parameters.minMaturity.toString());
|
|
1109
|
-
}
|
|
1110
|
-
if (parameters.maxMaturity !== void 0) {
|
|
1111
|
-
url.searchParams.set("max_maturity", parameters.maxMaturity.toString());
|
|
1112
|
-
}
|
|
1113
|
-
if (parameters.loanToken) {
|
|
1114
|
-
url.searchParams.set("loan_token", parameters.loanToken);
|
|
1115
|
-
}
|
|
1116
|
-
if (parameters.creator) {
|
|
1117
|
-
url.searchParams.set("creator", parameters.creator);
|
|
1118
|
-
}
|
|
1119
|
-
if (parameters.status?.length) {
|
|
1120
|
-
url.searchParams.set("status", parameters.status.join(","));
|
|
1121
|
-
}
|
|
1122
|
-
if (parameters.cursor) {
|
|
1899
|
+
async function getObligations(config, parameters) {
|
|
1900
|
+
const url = new URL(`${config.url.toString()}v1/obligations`);
|
|
1901
|
+
if (parameters?.cursor !== void 0) {
|
|
1123
1902
|
url.searchParams.set("cursor", parameters.cursor);
|
|
1124
1903
|
}
|
|
1125
|
-
if (parameters
|
|
1904
|
+
if (parameters?.limit !== void 0) {
|
|
1126
1905
|
url.searchParams.set("limit", parameters.limit.toString());
|
|
1127
1906
|
}
|
|
1128
|
-
const { cursor: returnedCursor, data:
|
|
1129
|
-
const
|
|
1907
|
+
const { cursor: returnedCursor, data: obligationsSnake } = await getApi(config, url);
|
|
1908
|
+
const obligations = obligationsSnake.map(Obligation_exports.fromSnakeCase);
|
|
1130
1909
|
return {
|
|
1131
1910
|
cursor: returnedCursor,
|
|
1132
|
-
|
|
1911
|
+
obligations
|
|
1133
1912
|
};
|
|
1134
1913
|
}
|
|
1135
1914
|
async function getApi(config, url) {
|
|
1136
1915
|
const pathname = url.pathname;
|
|
1137
1916
|
let action;
|
|
1138
1917
|
switch (true) {
|
|
1139
|
-
case pathname.includes("/v1/offers/match"):
|
|
1140
|
-
action = "match_offers";
|
|
1141
|
-
break;
|
|
1142
1918
|
case pathname.includes("/v1/offers"):
|
|
1143
1919
|
action = "get_offers";
|
|
1144
1920
|
break;
|
|
1921
|
+
case pathname.includes("/v1/obligations"):
|
|
1922
|
+
action = "get_obligations";
|
|
1923
|
+
break;
|
|
1145
1924
|
default:
|
|
1146
|
-
throw new
|
|
1925
|
+
throw new HttpGetApiFailedError("Unknown endpoint", {
|
|
1147
1926
|
details: `Unsupported path: ${pathname}`
|
|
1148
1927
|
});
|
|
1149
1928
|
}
|
|
1150
1929
|
const schemaParseResult = safeParse(action, Object.fromEntries(url.searchParams));
|
|
1151
1930
|
if (!schemaParseResult.success) {
|
|
1152
|
-
throw new
|
|
1931
|
+
throw new HttpGetApiFailedError(`Invalid URL parameters`, {
|
|
1153
1932
|
details: schemaParseResult.error.issues[0]?.message
|
|
1154
1933
|
});
|
|
1155
1934
|
}
|
|
@@ -1166,19 +1945,19 @@ async function getApi(config, url) {
|
|
|
1166
1945
|
case 429:
|
|
1167
1946
|
throw new HttpRateLimitError();
|
|
1168
1947
|
}
|
|
1169
|
-
throw new
|
|
1948
|
+
throw new HttpGetApiFailedError(`GET request returned ${response.status}`, {
|
|
1170
1949
|
details: await response.text()
|
|
1171
1950
|
});
|
|
1172
1951
|
}
|
|
1173
1952
|
return response.json();
|
|
1174
1953
|
}
|
|
1175
|
-
var InvalidUrlError = class extends
|
|
1954
|
+
var InvalidUrlError = class extends BaseError {
|
|
1176
1955
|
constructor(url) {
|
|
1177
1956
|
super(`URL "${url}" is not http/https.`);
|
|
1178
1957
|
__publicField(this, "name", "Router.InvalidUrlError");
|
|
1179
1958
|
}
|
|
1180
1959
|
};
|
|
1181
|
-
var HttpUnauthorizedError = class extends
|
|
1960
|
+
var HttpUnauthorizedError = class extends BaseError {
|
|
1182
1961
|
constructor() {
|
|
1183
1962
|
super("Unauthorized.", {
|
|
1184
1963
|
metaMessages: ["Ensure that an API key is provided."]
|
|
@@ -1186,7 +1965,7 @@ var HttpUnauthorizedError = class extends mempool.Errors.BaseError {
|
|
|
1186
1965
|
__publicField(this, "name", "Router.HttpUnauthorizedError");
|
|
1187
1966
|
}
|
|
1188
1967
|
};
|
|
1189
|
-
var HttpForbiddenError = class extends
|
|
1968
|
+
var HttpForbiddenError = class extends BaseError {
|
|
1190
1969
|
constructor() {
|
|
1191
1970
|
super("Forbidden.", {
|
|
1192
1971
|
metaMessages: ["Ensure that the API key is valid."]
|
|
@@ -1194,7 +1973,7 @@ var HttpForbiddenError = class extends mempool.Errors.BaseError {
|
|
|
1194
1973
|
__publicField(this, "name", "Router.HttpForbiddenError");
|
|
1195
1974
|
}
|
|
1196
1975
|
};
|
|
1197
|
-
var HttpRateLimitError = class extends
|
|
1976
|
+
var HttpRateLimitError = class extends BaseError {
|
|
1198
1977
|
constructor() {
|
|
1199
1978
|
super("Rate limit exceeded.", {
|
|
1200
1979
|
metaMessages: [
|
|
@@ -1204,16 +1983,16 @@ var HttpRateLimitError = class extends mempool.Errors.BaseError {
|
|
|
1204
1983
|
__publicField(this, "name", "Router.HttpRateLimitError");
|
|
1205
1984
|
}
|
|
1206
1985
|
};
|
|
1207
|
-
var
|
|
1986
|
+
var HttpGetApiFailedError = class extends BaseError {
|
|
1208
1987
|
constructor(message, { details } = {}) {
|
|
1209
1988
|
super(message, {
|
|
1210
1989
|
metaMessages: [details]
|
|
1211
1990
|
});
|
|
1212
|
-
__publicField(this, "name", "Router.
|
|
1991
|
+
__publicField(this, "name", "Router.HttpGetApiFailedError");
|
|
1213
1992
|
}
|
|
1214
1993
|
};
|
|
1215
1994
|
|
|
1216
|
-
// src/
|
|
1995
|
+
// src/collectors/validations/Validation.ts
|
|
1217
1996
|
var Validation_exports = {};
|
|
1218
1997
|
__export(Validation_exports, {
|
|
1219
1998
|
run: () => run
|
|
@@ -1260,17 +2039,17 @@ async function run(parameters) {
|
|
|
1260
2039
|
};
|
|
1261
2040
|
}
|
|
1262
2041
|
|
|
1263
|
-
// src/
|
|
2042
|
+
// src/collectors/validations/ValidationRule.ts
|
|
1264
2043
|
var ValidationRule_exports = {};
|
|
1265
2044
|
__export(ValidationRule_exports, {
|
|
1266
|
-
batch: () =>
|
|
2045
|
+
batch: () => batch2,
|
|
1267
2046
|
morpho: () => morpho,
|
|
1268
2047
|
single: () => single
|
|
1269
2048
|
});
|
|
1270
2049
|
function single(name, run2) {
|
|
1271
2050
|
return { kind: "single", name, run: run2 };
|
|
1272
2051
|
}
|
|
1273
|
-
function
|
|
2052
|
+
function batch2(name, run2) {
|
|
1274
2053
|
return { kind: "batch", name, run: run2 };
|
|
1275
2054
|
}
|
|
1276
2055
|
function morpho() {
|
|
@@ -1308,7 +2087,17 @@ function morpho() {
|
|
|
1308
2087
|
"buy_offers_non_empty_callback",
|
|
1309
2088
|
(offer, _) => {
|
|
1310
2089
|
if (offer.buy && offer.callback.data !== "0x") {
|
|
1311
|
-
|
|
2090
|
+
const allowed = new Set(
|
|
2091
|
+
Callback_exports.WhitelistedCallbackAddresses[Callback_exports.CallbackType.BuyVaultV1Callback].map(
|
|
2092
|
+
(a) => a.toLowerCase()
|
|
2093
|
+
)
|
|
2094
|
+
);
|
|
2095
|
+
const callbackAddress = offer.callback.address?.toLowerCase();
|
|
2096
|
+
if (!callbackAddress || !allowed.has(callbackAddress)) {
|
|
2097
|
+
return {
|
|
2098
|
+
message: "Buy offers with non-empty callback must use a whitelisted BuyVaultV1Callback."
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
1312
2101
|
}
|
|
1313
2102
|
}
|
|
1314
2103
|
);
|
|
@@ -1317,7 +2106,7 @@ function morpho() {
|
|
|
1317
2106
|
(offer, _) => {
|
|
1318
2107
|
if (!offer.buy && offer.callback.data !== "0x") {
|
|
1319
2108
|
const allowed = new Set(
|
|
1320
|
-
WhitelistedCallbackAddresses[
|
|
2109
|
+
Callback_exports.WhitelistedCallbackAddresses[Callback_exports.CallbackType.SellERC20Callback].map(
|
|
1321
2110
|
(a) => a.toLowerCase()
|
|
1322
2111
|
)
|
|
1323
2112
|
);
|
|
@@ -1333,10 +2122,7 @@ function morpho() {
|
|
|
1333
2122
|
(offer, _) => {
|
|
1334
2123
|
if (!offer.buy && offer.callback.data !== "0x") {
|
|
1335
2124
|
try {
|
|
1336
|
-
const decoded =
|
|
1337
|
-
type: "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */,
|
|
1338
|
-
data: offer.callback.data
|
|
1339
|
-
});
|
|
2125
|
+
const decoded = Callback_exports.decodeSellERC20Callback(offer.callback.data);
|
|
1340
2126
|
if (decoded.length === 0) {
|
|
1341
2127
|
return { message: "Sell offer callback data must include at least one collateral." };
|
|
1342
2128
|
}
|
|
@@ -1351,10 +2137,7 @@ function morpho() {
|
|
|
1351
2137
|
(offer, _) => {
|
|
1352
2138
|
if (!offer.buy && offer.callback.data !== "0x") {
|
|
1353
2139
|
try {
|
|
1354
|
-
const decoded =
|
|
1355
|
-
type: "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */,
|
|
1356
|
-
data: offer.callback.data
|
|
1357
|
-
});
|
|
2140
|
+
const decoded = Callback_exports.decodeSellERC20Callback(offer.callback.data);
|
|
1358
2141
|
const offerCollaterals = new Set(
|
|
1359
2142
|
offer.collaterals.map((c) => c.asset.toLowerCase())
|
|
1360
2143
|
);
|
|
@@ -1368,32 +2151,325 @@ function morpho() {
|
|
|
1368
2151
|
}
|
|
1369
2152
|
}
|
|
1370
2153
|
);
|
|
2154
|
+
const buyCallbackDataInvalid = single(
|
|
2155
|
+
"buy_offers_callback_data_invalid",
|
|
2156
|
+
(offer, _) => {
|
|
2157
|
+
if (offer.buy && offer.callback.data !== "0x") {
|
|
2158
|
+
try {
|
|
2159
|
+
const decoded = Callback_exports.decodeBuyVaultV1Callback(offer.callback.data);
|
|
2160
|
+
if (decoded.length === 0) {
|
|
2161
|
+
return { message: "Buy offer callback data must include at least one vault." };
|
|
2162
|
+
}
|
|
2163
|
+
} catch (_2) {
|
|
2164
|
+
return { message: "Buy offer callback data cannot be decoded." };
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
);
|
|
2169
|
+
const buyCallbackVaultInvalid = batch2(
|
|
2170
|
+
"buy_offers_callback_vault_invalid",
|
|
2171
|
+
async (offers, { client, chain }) => {
|
|
2172
|
+
const validationIssues = /* @__PURE__ */ new Map();
|
|
2173
|
+
const offersByVaultAddress = /* @__PURE__ */ new Map();
|
|
2174
|
+
for (let i = 0; i < offers.length; i++) {
|
|
2175
|
+
const offer = offers[i];
|
|
2176
|
+
if (offer.buy && offer.callback.data !== "0x") {
|
|
2177
|
+
try {
|
|
2178
|
+
const callbackVaults = Callback_exports.decodeBuyVaultV1Callback(offer.callback.data);
|
|
2179
|
+
for (const { vault } of callbackVaults) {
|
|
2180
|
+
const normalizedVaultAddress = vault.toLowerCase();
|
|
2181
|
+
if (!offersByVaultAddress.has(normalizedVaultAddress)) {
|
|
2182
|
+
offersByVaultAddress.set(normalizedVaultAddress, []);
|
|
2183
|
+
}
|
|
2184
|
+
offersByVaultAddress.get(normalizedVaultAddress).push({ index: i, offer });
|
|
2185
|
+
}
|
|
2186
|
+
} catch (_) {
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
const uniqueVaultAddresses = Array.from(offersByVaultAddress.keys());
|
|
2191
|
+
if (uniqueVaultAddresses.length === 0) return validationIssues;
|
|
2192
|
+
const whitelistedFactories = Object.values(chain.vaultV1Factory);
|
|
2193
|
+
const multicallContracts = [];
|
|
2194
|
+
for (const vaultAddress of uniqueVaultAddresses) {
|
|
2195
|
+
multicallContracts.push({
|
|
2196
|
+
address: vaultAddress,
|
|
2197
|
+
abi: Abi_exports.ERC4626,
|
|
2198
|
+
functionName: "asset"
|
|
2199
|
+
});
|
|
2200
|
+
for (const factoryAddress of whitelistedFactories) {
|
|
2201
|
+
multicallContracts.push({
|
|
2202
|
+
address: factoryAddress,
|
|
2203
|
+
abi: Abi_exports.MetaMorphoFactory,
|
|
2204
|
+
functionName: "isMetaMorpho",
|
|
2205
|
+
args: [vaultAddress]
|
|
2206
|
+
});
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
const multicallResults = await client.multicall({
|
|
2210
|
+
contracts: multicallContracts,
|
|
2211
|
+
allowFailure: true
|
|
2212
|
+
});
|
|
2213
|
+
const vaultAssetByAddress = /* @__PURE__ */ new Map();
|
|
2214
|
+
const registeredVaults = /* @__PURE__ */ new Set();
|
|
2215
|
+
const numberOfFactories = whitelistedFactories.length;
|
|
2216
|
+
let resultIndex = 0;
|
|
2217
|
+
for (const vaultAddress of uniqueVaultAddresses) {
|
|
2218
|
+
const assetCallResult = multicallResults[resultIndex++];
|
|
2219
|
+
const assetAddress = assetCallResult.status === "success" ? assetCallResult.result : null;
|
|
2220
|
+
vaultAssetByAddress.set(vaultAddress, assetAddress);
|
|
2221
|
+
let isRegisteredInFactory = false;
|
|
2222
|
+
for (let factoryIndex = 0; factoryIndex < numberOfFactories; factoryIndex++) {
|
|
2223
|
+
const factoryCallResult = multicallResults[resultIndex++];
|
|
2224
|
+
if (factoryCallResult.status === "success" && factoryCallResult.result === true) {
|
|
2225
|
+
isRegisteredInFactory = true;
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
if (isRegisteredInFactory) {
|
|
2229
|
+
registeredVaults.add(vaultAddress);
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
const uniqueOffers = /* @__PURE__ */ new Map();
|
|
2233
|
+
for (const offersArray of offersByVaultAddress.values()) {
|
|
2234
|
+
for (const { index, offer } of offersArray) {
|
|
2235
|
+
uniqueOffers.set(index, offer);
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
for (const [index, offer] of uniqueOffers) {
|
|
2239
|
+
try {
|
|
2240
|
+
const callbackVaults = Callback_exports.decodeBuyVaultV1Callback(offer.callback.data);
|
|
2241
|
+
const vaultsWithIssues = [];
|
|
2242
|
+
for (const { vault } of callbackVaults) {
|
|
2243
|
+
const normalizedVaultAddress = vault.toLowerCase();
|
|
2244
|
+
const assetAddress = vaultAssetByAddress.get(normalizedVaultAddress);
|
|
2245
|
+
const isRegistered = registeredVaults.has(normalizedVaultAddress);
|
|
2246
|
+
const failureReasons = [];
|
|
2247
|
+
if (assetAddress === null) {
|
|
2248
|
+
failureReasons.push("asset call failed");
|
|
2249
|
+
} else if (assetAddress && assetAddress.toLowerCase() !== offer.loanToken.toLowerCase()) {
|
|
2250
|
+
failureReasons.push("asset mismatch");
|
|
2251
|
+
}
|
|
2252
|
+
if (!isRegistered) {
|
|
2253
|
+
failureReasons.push("not registered in factory");
|
|
2254
|
+
}
|
|
2255
|
+
if (failureReasons.length > 0) {
|
|
2256
|
+
vaultsWithIssues.push({
|
|
2257
|
+
vaultAddress: vault,
|
|
2258
|
+
failureReasons: failureReasons.join(", ")
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
if (vaultsWithIssues.length > 0) {
|
|
2263
|
+
const failureDetails = vaultsWithIssues.map((v) => `${v.vaultAddress} (${v.failureReasons})`).join("; ");
|
|
2264
|
+
validationIssues.set(index, {
|
|
2265
|
+
message: `Buy offer callback vaults are invalid: ${failureDetails}`
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
} catch (_) {
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
return validationIssues;
|
|
2272
|
+
}
|
|
2273
|
+
);
|
|
2274
|
+
const maturity = single("maturity", (offer, _) => {
|
|
2275
|
+
const allowedMaturities = [Maturity_exports.from("end_of_month"), Maturity_exports.from("end_of_next_month")];
|
|
2276
|
+
if (!allowedMaturities.includes(offer.maturity)) {
|
|
2277
|
+
return {
|
|
2278
|
+
message: `Maturity must be end of current month (${allowedMaturities[0]}) or end of next month (${allowedMaturities[1]}). Got: ${offer.maturity}`
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
});
|
|
1371
2282
|
return [
|
|
1372
2283
|
chainId,
|
|
1373
2284
|
loanToken,
|
|
1374
2285
|
expiry,
|
|
2286
|
+
maturity,
|
|
1375
2287
|
// note: callback rules should be the last ones, since they do not mean that the offer is forever invalid
|
|
1376
2288
|
// integrators should be able to choose if they want to keep the offer or not
|
|
1377
2289
|
sellEmptyCallback,
|
|
1378
2290
|
buyNonEmptyCallback,
|
|
1379
2291
|
sellNonWhitelistedCallback,
|
|
1380
2292
|
sellCallbackDataInvalid,
|
|
1381
|
-
sellCallbackCollateralInvalid
|
|
2293
|
+
sellCallbackCollateralInvalid,
|
|
2294
|
+
buyCallbackDataInvalid,
|
|
2295
|
+
buyCallbackVaultInvalid
|
|
1382
2296
|
];
|
|
1383
2297
|
}
|
|
1384
2298
|
|
|
2299
|
+
// src/mempool/MempoolClient.ts
|
|
2300
|
+
var MempoolClient_exports = {};
|
|
2301
|
+
__export(MempoolClient_exports, {
|
|
2302
|
+
connect: () => connect2
|
|
2303
|
+
});
|
|
2304
|
+
var DEFAULT_BATCH_SIZE2 = 100;
|
|
2305
|
+
var DEFAULT_BLOCK_WINDOW2 = 100;
|
|
2306
|
+
function from8(parameters) {
|
|
2307
|
+
const config = {
|
|
2308
|
+
client: parameters.client,
|
|
2309
|
+
mempoolAddress: parameters.mempoolAddress,
|
|
2310
|
+
blockWindow: parameters.blockWindow || DEFAULT_BLOCK_WINDOW2
|
|
2311
|
+
};
|
|
2312
|
+
return {
|
|
2313
|
+
add: (parameters2) => add(config, parameters2),
|
|
2314
|
+
get: (parameters2) => get(config, parameters2),
|
|
2315
|
+
watch: (parameters2) => watch(config, parameters2),
|
|
2316
|
+
stream: (parameters2) => streamOffers(config, parameters2)
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
async function add(config, parameters) {
|
|
2320
|
+
const offer = Offer_exports.from(parameters.offer);
|
|
2321
|
+
if (!config.client.account) throw new WalletAccountNotSetError();
|
|
2322
|
+
const chainId = await getChainId(config.client);
|
|
2323
|
+
if (BigInt(chainId) !== offer.chainId)
|
|
2324
|
+
throw new ChainIdMismatchError(offer.chainId, BigInt(chainId));
|
|
2325
|
+
try {
|
|
2326
|
+
const tx = await config.client.sendTransaction({
|
|
2327
|
+
chain: config.client.chain,
|
|
2328
|
+
account: config.client.account,
|
|
2329
|
+
to: config.mempoolAddress,
|
|
2330
|
+
data: Offer_exports.encode(offer)
|
|
2331
|
+
});
|
|
2332
|
+
return { offer, txHash: tx };
|
|
2333
|
+
} catch (error) {
|
|
2334
|
+
throw new ViemClientError(error instanceof Error ? error.message : "Unknown error");
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
async function* get(config, parameters) {
|
|
2338
|
+
const {
|
|
2339
|
+
loanToken,
|
|
2340
|
+
blockNumberGte,
|
|
2341
|
+
blockNumberLte,
|
|
2342
|
+
order = "desc",
|
|
2343
|
+
options: { maxBatchSize = DEFAULT_BATCH_SIZE2 } = {}
|
|
2344
|
+
} = parameters || {};
|
|
2345
|
+
yield* streamOffers(config, {
|
|
2346
|
+
loanToken,
|
|
2347
|
+
order,
|
|
2348
|
+
blockNumberGte,
|
|
2349
|
+
blockNumberLte,
|
|
2350
|
+
options: { maxBatchSize, blockWindow: config.blockWindow }
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
function watch(config, parameters) {
|
|
2354
|
+
const {
|
|
2355
|
+
loanToken,
|
|
2356
|
+
lastSyncedBlock,
|
|
2357
|
+
polling: { interval = 3e4, maxBatchSize = DEFAULT_BATCH_SIZE2 } = {},
|
|
2358
|
+
onOffers
|
|
2359
|
+
} = parameters;
|
|
2360
|
+
return poll(
|
|
2361
|
+
async () => {
|
|
2362
|
+
const blockNumberGte = await lastSyncedBlock();
|
|
2363
|
+
const stream = streamOffers(config, {
|
|
2364
|
+
loanToken,
|
|
2365
|
+
order: "asc",
|
|
2366
|
+
blockNumberGte,
|
|
2367
|
+
options: { maxBatchSize, blockWindow: config.blockWindow }
|
|
2368
|
+
});
|
|
2369
|
+
for await (const { offers, blockNumber } of stream) {
|
|
2370
|
+
await onOffers(offers, blockNumber);
|
|
2371
|
+
}
|
|
2372
|
+
},
|
|
2373
|
+
{ interval }
|
|
2374
|
+
);
|
|
2375
|
+
}
|
|
2376
|
+
var chainIdCache = /* @__PURE__ */ new Map();
|
|
2377
|
+
var getChainId = async (client) => {
|
|
2378
|
+
if (chainIdCache.has(client.uid)) return chainIdCache.get(client.uid);
|
|
2379
|
+
const chainId = await client.getChainId();
|
|
2380
|
+
chainIdCache.set(client.uid, chainId);
|
|
2381
|
+
return chainId;
|
|
2382
|
+
};
|
|
2383
|
+
async function* streamOffers(config, parameters) {
|
|
2384
|
+
const {
|
|
2385
|
+
loanToken,
|
|
2386
|
+
blockNumberGte,
|
|
2387
|
+
blockNumberLte,
|
|
2388
|
+
order = "desc",
|
|
2389
|
+
options: { maxBatchSize = DEFAULT_BATCH_SIZE2, blockWindow = config.blockWindow } = {}
|
|
2390
|
+
} = parameters;
|
|
2391
|
+
const stream = Chain_exports.streamLogs({
|
|
2392
|
+
client: config.client.extend(viem.publicActions),
|
|
2393
|
+
contractAddress: config.mempoolAddress,
|
|
2394
|
+
event: {
|
|
2395
|
+
type: "event",
|
|
2396
|
+
name: "Event",
|
|
2397
|
+
inputs: [{ name: "data", type: "bytes", indexed: false, internalType: "bytes" }],
|
|
2398
|
+
anonymous: false
|
|
2399
|
+
},
|
|
2400
|
+
blockNumberGte,
|
|
2401
|
+
blockNumberLte,
|
|
2402
|
+
order,
|
|
2403
|
+
options: { maxBatchSize, blockWindow }
|
|
2404
|
+
});
|
|
2405
|
+
let blockNumber = order === "asc" ? blockNumberGte : blockNumberLte;
|
|
2406
|
+
for await (const { logs, blockNumber: newBlockNumber } of stream) {
|
|
2407
|
+
blockNumber = newBlockNumber;
|
|
2408
|
+
if (logs.length === 0) break;
|
|
2409
|
+
let offersAndBlockNumbers = logs.map((log) => {
|
|
2410
|
+
const [payload] = viem.decodeAbiParameters([{ type: "bytes" }], log.data);
|
|
2411
|
+
try {
|
|
2412
|
+
return { offer: Offer_exports.decode(payload, log.blockNumber), blockNumber: log.blockNumber };
|
|
2413
|
+
} catch (_) {
|
|
2414
|
+
return null;
|
|
2415
|
+
}
|
|
2416
|
+
}).filter((item) => item !== null);
|
|
2417
|
+
if (loanToken)
|
|
2418
|
+
offersAndBlockNumbers = offersAndBlockNumbers.filter(
|
|
2419
|
+
(o) => o.offer.loanToken.toLowerCase() === loanToken.toLowerCase()
|
|
2420
|
+
);
|
|
2421
|
+
if (offersAndBlockNumbers.length === 0) continue;
|
|
2422
|
+
yield {
|
|
2423
|
+
offers: offersAndBlockNumbers.map((item) => item.offer),
|
|
2424
|
+
blockNumber
|
|
2425
|
+
};
|
|
2426
|
+
}
|
|
2427
|
+
yield { offers: [], blockNumber };
|
|
2428
|
+
return;
|
|
2429
|
+
}
|
|
2430
|
+
var WalletAccountNotSetError = class extends BaseError {
|
|
2431
|
+
constructor() {
|
|
2432
|
+
super("Wallet account is not set.");
|
|
2433
|
+
__publicField(this, "name", "Mempool.WalletAccountNotSetError");
|
|
2434
|
+
}
|
|
2435
|
+
};
|
|
2436
|
+
var ViemClientError = class extends BaseError {
|
|
2437
|
+
constructor() {
|
|
2438
|
+
super(...arguments);
|
|
2439
|
+
__publicField(this, "name", "Mempool.ViemClientError");
|
|
2440
|
+
}
|
|
2441
|
+
};
|
|
2442
|
+
var ChainIdMismatchError = class extends BaseError {
|
|
2443
|
+
constructor(expected, actual) {
|
|
2444
|
+
super(`Chain ID mismatch. Offer chain ID is ${expected}, network chain ID is ${actual}.`);
|
|
2445
|
+
__publicField(this, "name", "Mempool.ChainIdMismatchError");
|
|
2446
|
+
}
|
|
2447
|
+
};
|
|
2448
|
+
|
|
2449
|
+
// src/mempool/MempoolClient.ts
|
|
2450
|
+
function connect2(parameters) {
|
|
2451
|
+
return from8(parameters);
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
exports.Abi = Abi_exports;
|
|
2455
|
+
exports.BrandTypeId = BrandTypeId;
|
|
1385
2456
|
exports.Callback = Callback_exports;
|
|
2457
|
+
exports.Chain = Chain_exports;
|
|
2458
|
+
exports.Collateral = Collateral_exports;
|
|
1386
2459
|
exports.Cursor = Cursor_exports;
|
|
2460
|
+
exports.Errors = Errors_exports;
|
|
2461
|
+
exports.Format = Format_exports;
|
|
2462
|
+
exports.LLTV = LLTV_exports;
|
|
1387
2463
|
exports.Liquidity = Liquidity_exports;
|
|
1388
|
-
exports.
|
|
1389
|
-
exports.
|
|
2464
|
+
exports.Maturity = Maturity_exports;
|
|
2465
|
+
exports.Mempool = MempoolClient_exports;
|
|
2466
|
+
exports.Obligation = Obligation_exports;
|
|
2467
|
+
exports.Offer = Offer_exports;
|
|
2468
|
+
exports.RouterApi = Schema_exports;
|
|
2469
|
+
exports.RouterClient = Client_exports;
|
|
2470
|
+
exports.Time = time_exports;
|
|
2471
|
+
exports.Utils = utils_exports;
|
|
1390
2472
|
exports.Validation = Validation_exports;
|
|
1391
2473
|
exports.ValidationRule = ValidationRule_exports;
|
|
1392
|
-
Object.keys(mempool).forEach(function (k) {
|
|
1393
|
-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
1394
|
-
enumerable: true,
|
|
1395
|
-
get: function () { return mempool[k]; }
|
|
1396
|
-
});
|
|
1397
|
-
});
|
|
1398
2474
|
//# sourceMappingURL=index.browser.js.map
|
|
1399
2475
|
//# sourceMappingURL=index.browser.js.map
|