@morpho-dev/router 0.1.11 → 0.1.12
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 +7 -7
- package/dist/drizzle/{offers_v1.1 → router_v1.1}/0000_init.sql +47 -39
- package/dist/drizzle/{offers_v1.1/meta/0007_snapshot.json → router_v1.1/meta/0000_snapshot.json} +21 -21
- package/dist/drizzle/router_v1.1/meta/_journal.json +13 -0
- package/dist/index.browser.d.cts +186 -159
- package/dist/index.browser.d.ts +186 -159
- package/dist/index.browser.js +807 -491
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +809 -493
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.cts +1795 -1759
- package/dist/index.node.d.ts +1795 -1759
- package/dist/index.node.js +2923 -2495
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +2925 -2496
- package/dist/index.node.mjs.map +1 -1
- package/package.json +4 -4
- 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/0006_snapshot.json +0 -884
- package/dist/drizzle/offers_v1.1/meta/_journal.json +0 -62
package/dist/index.browser.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
var mempool = require('@morpho-dev/mempool');
|
|
4
4
|
var viem = require('viem');
|
|
5
|
-
var jsBase64 = require('js-base64');
|
|
6
5
|
var v4 = require('zod/v4');
|
|
7
6
|
var zodOpenapi = require('zod-openapi');
|
|
7
|
+
var jsBase64 = require('js-base64');
|
|
8
8
|
|
|
9
9
|
var __defProp = Object.defineProperty;
|
|
10
10
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -14,157 +14,104 @@ var __export = (target, all) => {
|
|
|
14
14
|
};
|
|
15
15
|
var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
|
|
16
16
|
|
|
17
|
-
// src/
|
|
18
|
-
var
|
|
19
|
-
__export(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
// src/api/Client.ts
|
|
18
|
+
var Client_exports = {};
|
|
19
|
+
__export(Client_exports, {
|
|
20
|
+
HttpForbiddenError: () => HttpForbiddenError,
|
|
21
|
+
HttpGetOffersFailedError: () => HttpGetOffersFailedError,
|
|
22
|
+
HttpRateLimitError: () => HttpRateLimitError,
|
|
23
|
+
HttpUnauthorizedError: () => HttpUnauthorizedError,
|
|
24
|
+
InvalidUrlError: () => InvalidUrlError,
|
|
25
|
+
connect: () => connect,
|
|
26
|
+
get: () => get,
|
|
27
|
+
match: () => match
|
|
26
28
|
});
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
|
|
30
|
+
// src/core/RouterOffer.ts
|
|
31
|
+
var RouterOffer_exports = {};
|
|
32
|
+
__export(RouterOffer_exports, {
|
|
33
|
+
InvalidRouterOfferError: () => InvalidRouterOfferError,
|
|
34
|
+
OfferStatusValues: () => OfferStatusValues,
|
|
35
|
+
RouterOfferSchema: () => RouterOfferSchema,
|
|
36
|
+
consumedEvent: () => consumedEvent,
|
|
37
|
+
from: () => from,
|
|
38
|
+
fromConsumedLog: () => fromConsumedLog,
|
|
39
|
+
fromSnakeCase: () => fromSnakeCase,
|
|
40
|
+
random: () => random,
|
|
41
|
+
toSnakeCase: () => toSnakeCase
|
|
42
|
+
});
|
|
43
|
+
var OfferStatusValues = [
|
|
44
|
+
"valid",
|
|
45
|
+
"callback_not_supported",
|
|
46
|
+
"callback_error",
|
|
47
|
+
"unverified"
|
|
48
|
+
];
|
|
49
|
+
var RouterOfferSchema = (parameters) => mempool.Offer.OfferSchema(parameters).extend({
|
|
50
|
+
consumed: v4.z.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
51
|
+
status: v4.z.enum(OfferStatusValues),
|
|
52
|
+
metadata: v4.z.object({
|
|
53
|
+
issue: v4.z.string()
|
|
54
|
+
}).optional()
|
|
55
|
+
});
|
|
56
|
+
var consumedEvent = {
|
|
57
|
+
type: "event",
|
|
58
|
+
name: "Consumed",
|
|
59
|
+
inputs: [
|
|
60
|
+
{ name: "user", type: "address", indexed: true, internalType: "address" },
|
|
61
|
+
{ name: "nonce", type: "uint256", indexed: true, internalType: "uint256" },
|
|
62
|
+
{ name: "amount", type: "uint256", indexed: false, internalType: "uint256" }
|
|
63
|
+
],
|
|
64
|
+
anonymous: false
|
|
39
65
|
};
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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`);
|
|
116
|
-
}
|
|
66
|
+
function from(input) {
|
|
67
|
+
try {
|
|
68
|
+
const parsedOffer = RouterOfferSchema({ omitHash: true }).parse(input);
|
|
69
|
+
const parsedHash = mempool.Offer.OfferHashSchema.parse(mempool.Offer.hash(parsedOffer));
|
|
70
|
+
return {
|
|
71
|
+
...parsedOffer,
|
|
72
|
+
hash: parsedHash
|
|
73
|
+
};
|
|
74
|
+
} catch (error) {
|
|
75
|
+
throw new InvalidRouterOfferError(error);
|
|
117
76
|
}
|
|
118
77
|
}
|
|
119
|
-
function
|
|
120
|
-
|
|
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;
|
|
78
|
+
function fromSnakeCase(input) {
|
|
79
|
+
return from(mempool.Format.fromSnakeCase(input));
|
|
129
80
|
}
|
|
130
|
-
function
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
const [collaterals, amounts] = viem.decodeAbiParameters(
|
|
134
|
-
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
135
|
-
data
|
|
136
|
-
);
|
|
137
|
-
if (collaterals.length !== amounts.length) {
|
|
138
|
-
throw new Error("Mismatched array lengths");
|
|
139
|
-
}
|
|
140
|
-
return collaterals.map((c, i) => ({ collateral: c, amount: amounts[i] }));
|
|
141
|
-
} catch (_) {
|
|
142
|
-
throw new Error("Invalid SellWithdrawFromWallet callback data");
|
|
143
|
-
}
|
|
81
|
+
function toSnakeCase(offer) {
|
|
82
|
+
return mempool.Format.toSnakeCase(offer);
|
|
144
83
|
}
|
|
145
|
-
function
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
84
|
+
function random() {
|
|
85
|
+
const baseOffer = mempool.Offer.random();
|
|
86
|
+
return from({
|
|
87
|
+
...baseOffer,
|
|
88
|
+
status: "valid",
|
|
89
|
+
metadata: void 0,
|
|
90
|
+
consumed: 0n
|
|
91
|
+
});
|
|
151
92
|
}
|
|
152
|
-
function
|
|
153
|
-
const {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
93
|
+
function fromConsumedLog(parameters) {
|
|
94
|
+
const { blockNumber, logIndex, chainId, transactionHash, user, nonce, amount } = parameters;
|
|
95
|
+
return {
|
|
96
|
+
id: `${blockNumber.toString()}-${logIndex.toString()}-${chainId}-${transactionHash}`,
|
|
97
|
+
chainId: BigInt(chainId),
|
|
98
|
+
offering: user,
|
|
99
|
+
nonce,
|
|
100
|
+
amount
|
|
101
|
+
};
|
|
161
102
|
}
|
|
103
|
+
var InvalidRouterOfferError = class extends mempool.Errors.BaseError {
|
|
104
|
+
constructor(error) {
|
|
105
|
+
super("Invalid router offer.", { cause: error });
|
|
106
|
+
__publicField(this, "name", "RouterOffer.InvalidRouterOfferError");
|
|
107
|
+
}
|
|
108
|
+
};
|
|
162
109
|
|
|
163
110
|
// src/core/Cursor.ts
|
|
164
111
|
var Cursor_exports = {};
|
|
165
112
|
__export(Cursor_exports, {
|
|
166
|
-
decode: () =>
|
|
167
|
-
encode: () =>
|
|
113
|
+
decode: () => decode,
|
|
114
|
+
encode: () => encode,
|
|
168
115
|
validate: () => validate
|
|
169
116
|
});
|
|
170
117
|
function validate(cursor) {
|
|
@@ -236,242 +183,17 @@ function validate(cursor) {
|
|
|
236
183
|
}
|
|
237
184
|
return true;
|
|
238
185
|
}
|
|
239
|
-
function
|
|
186
|
+
function encode(c) {
|
|
240
187
|
return jsBase64.Base64.encodeURL(JSON.stringify(c));
|
|
241
188
|
}
|
|
242
|
-
function
|
|
189
|
+
function decode(token) {
|
|
243
190
|
if (!token) return null;
|
|
244
191
|
const decoded = JSON.parse(jsBase64.Base64.decode(token));
|
|
245
192
|
validate(decoded);
|
|
246
193
|
return decoded;
|
|
247
194
|
}
|
|
248
195
|
|
|
249
|
-
// src/
|
|
250
|
-
var Liquidity_exports = {};
|
|
251
|
-
__export(Liquidity_exports, {
|
|
252
|
-
fetch: () => fetch2,
|
|
253
|
-
fetchBalancesAndAllowances: () => fetchBalancesAndAllowances,
|
|
254
|
-
serialize: () => serialize
|
|
255
|
-
});
|
|
256
|
-
async function fetchBalancesAndAllowances(parameters) {
|
|
257
|
-
const { client, spender, pairs, options } = parameters;
|
|
258
|
-
if (pairs.length === 0) return /* @__PURE__ */ new Map();
|
|
259
|
-
const batchSize = Math.max(1, options?.batchSize ?? 5e3);
|
|
260
|
-
const retryAttempts = Math.max(1, options?.retryAttempts ?? 3);
|
|
261
|
-
const retryDelayMs = Math.max(0, options?.retryDelayMs ?? 50);
|
|
262
|
-
const blockNumber = options?.blockNumber ? BigInt(options.blockNumber) : void 0;
|
|
263
|
-
const out = /* @__PURE__ */ new Map();
|
|
264
|
-
for (const pairsBatch of mempool.Utils.batch(pairs, batchSize)) {
|
|
265
|
-
const balanceContracts = [];
|
|
266
|
-
const allowanceContracts = [];
|
|
267
|
-
for (const { user, token } of pairsBatch) {
|
|
268
|
-
balanceContracts.push({
|
|
269
|
-
address: token,
|
|
270
|
-
abi: viem.erc20Abi,
|
|
271
|
-
functionName: "balanceOf",
|
|
272
|
-
args: [user]
|
|
273
|
-
});
|
|
274
|
-
allowanceContracts.push({
|
|
275
|
-
address: token,
|
|
276
|
-
abi: viem.erc20Abi,
|
|
277
|
-
functionName: "allowance",
|
|
278
|
-
args: [user, spender]
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
const [balances, allowances] = await Promise.all([
|
|
282
|
-
mempool.Utils.retry(
|
|
283
|
-
() => client.multicall({
|
|
284
|
-
allowFailure: false,
|
|
285
|
-
contracts: balanceContracts,
|
|
286
|
-
...blockNumber ? { blockNumber } : {}
|
|
287
|
-
}),
|
|
288
|
-
retryAttempts,
|
|
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);
|
|
309
|
-
}
|
|
310
|
-
perUser.set(token, { balance, allowance });
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return out;
|
|
314
|
-
}
|
|
315
|
-
async function fetch2(parameters) {
|
|
316
|
-
const { client, chainId, spender, type, pairs, options } = parameters;
|
|
317
|
-
if (type !== "buy_with_empty_callback" /* BuyWithEmptyCallback */)
|
|
318
|
-
throw new Error(`CallbackType not implemented: ${type}`);
|
|
319
|
-
const map = await fetchBalancesAndAllowances({
|
|
320
|
-
client,
|
|
321
|
-
spender,
|
|
322
|
-
pairs: pairs.map(({ user, loanToken }) => ({ user, token: loanToken })),
|
|
323
|
-
options
|
|
324
|
-
});
|
|
325
|
-
const out = [];
|
|
326
|
-
for (const [user, perLoanToken] of map) {
|
|
327
|
-
for (const [loanToken, { balance, allowance }] of perLoanToken) {
|
|
328
|
-
const amount = balance < allowance ? balance : allowance;
|
|
329
|
-
out.push(
|
|
330
|
-
buildLiquidity({
|
|
331
|
-
type,
|
|
332
|
-
user,
|
|
333
|
-
loanToken,
|
|
334
|
-
chainId,
|
|
335
|
-
amount,
|
|
336
|
-
index: 0
|
|
337
|
-
})
|
|
338
|
-
);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
return out;
|
|
342
|
-
}
|
|
343
|
-
function serialize(liquidity) {
|
|
344
|
-
const normalized = {
|
|
345
|
-
userPosition: {
|
|
346
|
-
id: liquidity.userPosition.id,
|
|
347
|
-
availableLiquidityQueueId: liquidity.userPosition.availableLiquidityQueueId,
|
|
348
|
-
user: liquidity.userPosition.user,
|
|
349
|
-
chainId: String(liquidity.userPosition.chainId),
|
|
350
|
-
amount: String(liquidity.userPosition.amount)
|
|
351
|
-
},
|
|
352
|
-
queues: liquidity.queues.map((queueWithPool) => ({
|
|
353
|
-
queue: {
|
|
354
|
-
queueId: queueWithPool.queue.queueId,
|
|
355
|
-
availableLiquidityPoolId: queueWithPool.queue.availableLiquidityPoolId,
|
|
356
|
-
index: queueWithPool.queue.index
|
|
357
|
-
},
|
|
358
|
-
pool: {
|
|
359
|
-
id: queueWithPool.pool.id,
|
|
360
|
-
amount: String(queueWithPool.pool.amount)
|
|
361
|
-
}
|
|
362
|
-
})).sort(
|
|
363
|
-
(left, right) => {
|
|
364
|
-
const leftQueueId = left.queue.queueId || "";
|
|
365
|
-
const rightQueueId = right.queue.queueId || "";
|
|
366
|
-
if (leftQueueId < rightQueueId) return -1;
|
|
367
|
-
if (leftQueueId > rightQueueId) return 1;
|
|
368
|
-
const leftPoolId = left.pool.id;
|
|
369
|
-
const rightPoolId = right.pool.id;
|
|
370
|
-
if (leftPoolId < rightPoolId) return -1;
|
|
371
|
-
if (leftPoolId > rightPoolId) return 1;
|
|
372
|
-
const leftIndex = left.queue.index;
|
|
373
|
-
const rightIndex = right.queue.index;
|
|
374
|
-
if (leftIndex < rightIndex) return -1;
|
|
375
|
-
if (leftIndex > rightIndex) return 1;
|
|
376
|
-
return 0;
|
|
377
|
-
}
|
|
378
|
-
)
|
|
379
|
-
};
|
|
380
|
-
return JSON.stringify(normalized);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// src/core/RouterOffer.ts
|
|
384
|
-
var RouterOffer_exports = {};
|
|
385
|
-
__export(RouterOffer_exports, {
|
|
386
|
-
InvalidRouterOfferError: () => InvalidRouterOfferError,
|
|
387
|
-
OfferStatusValues: () => OfferStatusValues,
|
|
388
|
-
RouterOfferSchema: () => RouterOfferSchema,
|
|
389
|
-
consumedEvent: () => consumedEvent,
|
|
390
|
-
from: () => from,
|
|
391
|
-
fromConsumedLog: () => fromConsumedLog,
|
|
392
|
-
fromSnakeCase: () => fromSnakeCase,
|
|
393
|
-
random: () => random,
|
|
394
|
-
toSnakeCase: () => toSnakeCase
|
|
395
|
-
});
|
|
396
|
-
var OfferStatusValues = [
|
|
397
|
-
"valid",
|
|
398
|
-
"callback_not_supported",
|
|
399
|
-
"callback_error",
|
|
400
|
-
"unverified"
|
|
401
|
-
];
|
|
402
|
-
var RouterOfferSchema = (parameters) => mempool.Offer.OfferSchema(parameters).extend({
|
|
403
|
-
consumed: v4.z.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
404
|
-
status: v4.z.enum(OfferStatusValues),
|
|
405
|
-
metadata: v4.z.object({
|
|
406
|
-
issue: v4.z.string()
|
|
407
|
-
}).optional()
|
|
408
|
-
});
|
|
409
|
-
var consumedEvent = {
|
|
410
|
-
type: "event",
|
|
411
|
-
name: "Consumed",
|
|
412
|
-
inputs: [
|
|
413
|
-
{ name: "user", type: "address", indexed: true, internalType: "address" },
|
|
414
|
-
{ name: "nonce", type: "uint256", indexed: true, internalType: "uint256" },
|
|
415
|
-
{ name: "amount", type: "uint256", indexed: false, internalType: "uint256" }
|
|
416
|
-
],
|
|
417
|
-
anonymous: false
|
|
418
|
-
};
|
|
419
|
-
function from(input) {
|
|
420
|
-
try {
|
|
421
|
-
const parsedOffer = RouterOfferSchema({ omitHash: true }).parse(input);
|
|
422
|
-
const parsedHash = mempool.Offer.OfferHashSchema.parse(mempool.Offer.hash(parsedOffer));
|
|
423
|
-
return {
|
|
424
|
-
...parsedOffer,
|
|
425
|
-
hash: parsedHash
|
|
426
|
-
};
|
|
427
|
-
} catch (error) {
|
|
428
|
-
throw new InvalidRouterOfferError(error);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
function fromSnakeCase(input) {
|
|
432
|
-
return from(mempool.Format.fromSnakeCase(input));
|
|
433
|
-
}
|
|
434
|
-
function toSnakeCase(offer) {
|
|
435
|
-
return mempool.Format.toSnakeCase(offer);
|
|
436
|
-
}
|
|
437
|
-
function random() {
|
|
438
|
-
const baseOffer = mempool.Offer.random();
|
|
439
|
-
return from({
|
|
440
|
-
...baseOffer,
|
|
441
|
-
status: "valid",
|
|
442
|
-
metadata: void 0,
|
|
443
|
-
consumed: 0n
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
function fromConsumedLog(parameters) {
|
|
447
|
-
const { blockNumber, logIndex, chainId, transactionHash, user, nonce, amount } = parameters;
|
|
448
|
-
return {
|
|
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
|
|
474
|
-
});
|
|
196
|
+
// src/api/Schema/requests.ts
|
|
475
197
|
var MAX_LIMIT = 100;
|
|
476
198
|
var DEFAULT_LIMIT = 20;
|
|
477
199
|
var MAX_LLTV = 100;
|
|
@@ -648,7 +370,7 @@ var GetOffersQueryParams = v4.z.object({
|
|
|
648
370
|
(val) => {
|
|
649
371
|
if (!val) return true;
|
|
650
372
|
try {
|
|
651
|
-
const decoded =
|
|
373
|
+
const decoded = decode(val);
|
|
652
374
|
return decoded !== null;
|
|
653
375
|
} catch (_error) {
|
|
654
376
|
return false;
|
|
@@ -820,7 +542,7 @@ var MatchOffersQueryParams = v4.z.object({
|
|
|
820
542
|
(val) => {
|
|
821
543
|
if (!val) return true;
|
|
822
544
|
try {
|
|
823
|
-
const decoded =
|
|
545
|
+
const decoded = decode(val);
|
|
824
546
|
return decoded !== null;
|
|
825
547
|
} catch (_error) {
|
|
826
548
|
return false;
|
|
@@ -860,7 +582,7 @@ function safeParse(action, query, error) {
|
|
|
860
582
|
});
|
|
861
583
|
}
|
|
862
584
|
|
|
863
|
-
// src/
|
|
585
|
+
// src/api/Schema/openapi.ts
|
|
864
586
|
var successResponseSchema = v4.z.object({
|
|
865
587
|
status: v4.z.literal("success"),
|
|
866
588
|
cursor: v4.z.string().nullable(),
|
|
@@ -963,7 +685,7 @@ zodOpenapi.createDocument({
|
|
|
963
685
|
paths
|
|
964
686
|
});
|
|
965
687
|
|
|
966
|
-
// src/
|
|
688
|
+
// src/api/Schema/utils.ts
|
|
967
689
|
function toResponse(routerOffer) {
|
|
968
690
|
const { consumed, status, metadata, ...offer } = routerOffer;
|
|
969
691
|
return {
|
|
@@ -983,7 +705,7 @@ function fromResponse(offerResponse) {
|
|
|
983
705
|
};
|
|
984
706
|
}
|
|
985
707
|
|
|
986
|
-
// src/
|
|
708
|
+
// src/api/Client.ts
|
|
987
709
|
function connect(opts) {
|
|
988
710
|
const u = new URL(opts?.url || "https://router.morpho.dev");
|
|
989
711
|
if (u.protocol !== "http:" && u.protocol !== "https:") {
|
|
@@ -1083,135 +805,720 @@ async function get(config, parameters) {
|
|
|
1083
805
|
if (parameters.limit !== void 0) {
|
|
1084
806
|
url.searchParams.set("limit", parameters.limit.toString());
|
|
1085
807
|
}
|
|
1086
|
-
const { cursor: returnedCursor, data: offers } = await getApi(config, url);
|
|
1087
|
-
const routerOffers = offers.map(mempool.Format.fromSnakeCase).map(fromResponse);
|
|
1088
|
-
return {
|
|
1089
|
-
cursor: returnedCursor,
|
|
1090
|
-
offers: routerOffers.map(from).map(toResponse)
|
|
1091
|
-
};
|
|
808
|
+
const { cursor: returnedCursor, data: offers } = await getApi(config, url);
|
|
809
|
+
const routerOffers = offers.map(mempool.Format.fromSnakeCase).map(fromResponse);
|
|
810
|
+
return {
|
|
811
|
+
cursor: returnedCursor,
|
|
812
|
+
offers: routerOffers.map(from).map(toResponse)
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
async function match(config, parameters) {
|
|
816
|
+
const url = new URL(`${config.url.toString()}v1/offers/match`);
|
|
817
|
+
url.searchParams.set("side", parameters.side);
|
|
818
|
+
url.searchParams.set("chain_id", parameters.chainId.toString());
|
|
819
|
+
if (parameters.rate !== void 0) {
|
|
820
|
+
url.searchParams.set("rate", parameters.rate.toString());
|
|
821
|
+
}
|
|
822
|
+
if (parameters.collaterals?.length) {
|
|
823
|
+
const collateralsStr = parameters.collaterals.map(({ asset, oracle, lltv }) => `${asset}:${oracle}:${viem.formatUnits(lltv, 16)}`).join("#");
|
|
824
|
+
url.searchParams.set("collaterals", collateralsStr);
|
|
825
|
+
}
|
|
826
|
+
if (parameters.maturity !== void 0) {
|
|
827
|
+
url.searchParams.set("maturity", parameters.maturity.toString());
|
|
828
|
+
}
|
|
829
|
+
if (parameters.minMaturity !== void 0) {
|
|
830
|
+
url.searchParams.set("min_maturity", parameters.minMaturity.toString());
|
|
831
|
+
}
|
|
832
|
+
if (parameters.maxMaturity !== void 0) {
|
|
833
|
+
url.searchParams.set("max_maturity", parameters.maxMaturity.toString());
|
|
834
|
+
}
|
|
835
|
+
if (parameters.loanToken) {
|
|
836
|
+
url.searchParams.set("loan_token", parameters.loanToken);
|
|
837
|
+
}
|
|
838
|
+
if (parameters.creator) {
|
|
839
|
+
url.searchParams.set("creator", parameters.creator);
|
|
840
|
+
}
|
|
841
|
+
if (parameters.status?.length) {
|
|
842
|
+
url.searchParams.set("status", parameters.status.join(","));
|
|
843
|
+
}
|
|
844
|
+
if (parameters.cursor) {
|
|
845
|
+
url.searchParams.set("cursor", parameters.cursor);
|
|
846
|
+
}
|
|
847
|
+
if (parameters.limit !== void 0) {
|
|
848
|
+
url.searchParams.set("limit", parameters.limit.toString());
|
|
849
|
+
}
|
|
850
|
+
const { cursor: returnedCursor, data: offers } = await getApi(config, url);
|
|
851
|
+
const routerOffers = offers.map(mempool.Format.fromSnakeCase).map(fromResponse);
|
|
852
|
+
return {
|
|
853
|
+
cursor: returnedCursor,
|
|
854
|
+
offers: routerOffers.map(from).map(toResponse)
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
async function getApi(config, url) {
|
|
858
|
+
const pathname = url.pathname;
|
|
859
|
+
let action;
|
|
860
|
+
switch (true) {
|
|
861
|
+
case pathname.includes("/v1/offers/match"):
|
|
862
|
+
action = "match_offers";
|
|
863
|
+
break;
|
|
864
|
+
case pathname.includes("/v1/offers"):
|
|
865
|
+
action = "get_offers";
|
|
866
|
+
break;
|
|
867
|
+
default:
|
|
868
|
+
throw new HttpGetOffersFailedError("Unknown endpoint", {
|
|
869
|
+
details: `Unsupported path: ${pathname}`
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
const schemaParseResult = safeParse(action, Object.fromEntries(url.searchParams));
|
|
873
|
+
if (!schemaParseResult.success) {
|
|
874
|
+
throw new HttpGetOffersFailedError(`Invalid URL parameters`, {
|
|
875
|
+
details: schemaParseResult.error.issues[0]?.message
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
const response = await fetch(url.toString(), {
|
|
879
|
+
method: "GET",
|
|
880
|
+
headers: config.headers
|
|
881
|
+
});
|
|
882
|
+
if (!response.ok) {
|
|
883
|
+
switch (response.status) {
|
|
884
|
+
case 401:
|
|
885
|
+
throw new HttpUnauthorizedError();
|
|
886
|
+
case 403:
|
|
887
|
+
throw new HttpForbiddenError();
|
|
888
|
+
case 429:
|
|
889
|
+
throw new HttpRateLimitError();
|
|
890
|
+
}
|
|
891
|
+
throw new HttpGetOffersFailedError(`GET request returned ${response.status}`, {
|
|
892
|
+
details: await response.text()
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
return response.json();
|
|
896
|
+
}
|
|
897
|
+
var InvalidUrlError = class extends mempool.Errors.BaseError {
|
|
898
|
+
constructor(url) {
|
|
899
|
+
super(`URL "${url}" is not http/https.`);
|
|
900
|
+
__publicField(this, "name", "Router.InvalidUrlError");
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
var HttpUnauthorizedError = class extends mempool.Errors.BaseError {
|
|
904
|
+
constructor() {
|
|
905
|
+
super("Unauthorized.", {
|
|
906
|
+
metaMessages: ["Ensure that an API key is provided."]
|
|
907
|
+
});
|
|
908
|
+
__publicField(this, "name", "Router.HttpUnauthorizedError");
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
var HttpForbiddenError = class extends mempool.Errors.BaseError {
|
|
912
|
+
constructor() {
|
|
913
|
+
super("Forbidden.", {
|
|
914
|
+
metaMessages: ["Ensure that the API key is valid."]
|
|
915
|
+
});
|
|
916
|
+
__publicField(this, "name", "Router.HttpForbiddenError");
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
var HttpRateLimitError = class extends mempool.Errors.BaseError {
|
|
920
|
+
constructor() {
|
|
921
|
+
super("Rate limit exceeded.", {
|
|
922
|
+
metaMessages: [
|
|
923
|
+
"The number of allowed requests has been exceeded. You must wait for the rate limit to reset."
|
|
924
|
+
]
|
|
925
|
+
});
|
|
926
|
+
__publicField(this, "name", "Router.HttpRateLimitError");
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
var HttpGetOffersFailedError = class extends mempool.Errors.BaseError {
|
|
930
|
+
constructor(message, { details } = {}) {
|
|
931
|
+
super(message, {
|
|
932
|
+
metaMessages: [details]
|
|
933
|
+
});
|
|
934
|
+
__publicField(this, "name", "Router.HttpGetOffersFailedError");
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
|
|
938
|
+
// src/core/Callback.ts
|
|
939
|
+
var Callback_exports = {};
|
|
940
|
+
__export(Callback_exports, {
|
|
941
|
+
CallbackType: () => CallbackType,
|
|
942
|
+
WhitelistedCallbackAddresses: () => WhitelistedCallbackAddresses,
|
|
943
|
+
buildLiquidity: () => buildLiquidity,
|
|
944
|
+
decode: () => decode2,
|
|
945
|
+
encode: () => encode2,
|
|
946
|
+
getCallbackIdForOffer: () => getCallbackIdForOffer
|
|
947
|
+
});
|
|
948
|
+
var CallbackType = /* @__PURE__ */ ((CallbackType2) => {
|
|
949
|
+
CallbackType2["BuyWithEmptyCallback"] = "buy_with_empty_callback";
|
|
950
|
+
CallbackType2["SellERC20Callback"] = "sell_erc20_callback";
|
|
951
|
+
return CallbackType2;
|
|
952
|
+
})(CallbackType || {});
|
|
953
|
+
var WhitelistedCallbackAddresses = {
|
|
954
|
+
["buy_with_empty_callback" /* BuyWithEmptyCallback */]: [],
|
|
955
|
+
["sell_erc20_callback" /* SellERC20Callback */]: [
|
|
956
|
+
"0x1111111111111111111111111111111111111111",
|
|
957
|
+
"0x2222222222222222222222222222222222222222"
|
|
958
|
+
// @TODO: update once deployed and add mapping per chain if needed
|
|
959
|
+
].map((address) => address.toLowerCase())
|
|
960
|
+
};
|
|
961
|
+
function buildLiquidity(parameters) {
|
|
962
|
+
switch (parameters.type) {
|
|
963
|
+
case "buy_with_empty_callback" /* BuyWithEmptyCallback */: {
|
|
964
|
+
const { user, loanToken, chainId, amount, index = 0, updatedAt = /* @__PURE__ */ new Date() } = parameters;
|
|
965
|
+
const amountStr = amount.toString();
|
|
966
|
+
const id = `${user}-${chainId.toString()}-${parameters.type}-${loanToken}`.toLowerCase();
|
|
967
|
+
const poolId = `${user}-${chainId.toString()}-${loanToken}`.toLowerCase();
|
|
968
|
+
return {
|
|
969
|
+
userPosition: {
|
|
970
|
+
id,
|
|
971
|
+
availableLiquidityQueueId: id,
|
|
972
|
+
user: user.toLowerCase(),
|
|
973
|
+
chainId,
|
|
974
|
+
amount: amountStr,
|
|
975
|
+
updatedAt
|
|
976
|
+
},
|
|
977
|
+
queues: [
|
|
978
|
+
{
|
|
979
|
+
queue: {
|
|
980
|
+
queueId: id,
|
|
981
|
+
availableLiquidityPoolId: poolId,
|
|
982
|
+
index,
|
|
983
|
+
callbackAmount: "0",
|
|
984
|
+
updatedAt
|
|
985
|
+
},
|
|
986
|
+
pool: {
|
|
987
|
+
id: poolId,
|
|
988
|
+
amount: amountStr,
|
|
989
|
+
updatedAt
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
]
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
case "sell_erc20_callback" /* SellERC20Callback */: {
|
|
996
|
+
const {
|
|
997
|
+
user,
|
|
998
|
+
termId,
|
|
999
|
+
offerHash,
|
|
1000
|
+
chainId,
|
|
1001
|
+
amount,
|
|
1002
|
+
collaterals,
|
|
1003
|
+
index = 0,
|
|
1004
|
+
updatedAt = /* @__PURE__ */ new Date()
|
|
1005
|
+
} = parameters;
|
|
1006
|
+
const amountStr = amount.toString();
|
|
1007
|
+
const id = `${user}-${chainId.toString()}-${parameters.type}-${termId}-${offerHash}`.toLowerCase();
|
|
1008
|
+
return {
|
|
1009
|
+
userPosition: {
|
|
1010
|
+
id,
|
|
1011
|
+
availableLiquidityQueueId: id,
|
|
1012
|
+
user: user.toLowerCase(),
|
|
1013
|
+
chainId,
|
|
1014
|
+
amount: amountStr,
|
|
1015
|
+
updatedAt
|
|
1016
|
+
},
|
|
1017
|
+
queues: collaterals.map((collateral) => {
|
|
1018
|
+
const poolId = `${user}-${chainId.toString()}-${collateral.collateralAddress}`.toLowerCase();
|
|
1019
|
+
return {
|
|
1020
|
+
queue: {
|
|
1021
|
+
queueId: id,
|
|
1022
|
+
availableLiquidityPoolId: poolId,
|
|
1023
|
+
index,
|
|
1024
|
+
callbackAmount: collateral.callbackAmount.toString(),
|
|
1025
|
+
updatedAt
|
|
1026
|
+
},
|
|
1027
|
+
pool: {
|
|
1028
|
+
id: poolId,
|
|
1029
|
+
amount: collateral.balance.toString(),
|
|
1030
|
+
updatedAt
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
})
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
default: {
|
|
1037
|
+
throw new Error(`CallbackType not implemented`);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
function getCallbackIdForOffer(offer) {
|
|
1042
|
+
if (offer.buy && offer.callback.data === "0x") {
|
|
1043
|
+
return `${offer.offering}-${offer.chainId.toString()}-${"buy_with_empty_callback" /* BuyWithEmptyCallback */}-${offer.loanToken}`.toLowerCase();
|
|
1044
|
+
}
|
|
1045
|
+
if (!offer.buy && offer.callback.data !== "0x" && WhitelistedCallbackAddresses["sell_erc20_callback" /* SellERC20Callback */].includes(
|
|
1046
|
+
offer.callback.address.toLowerCase()
|
|
1047
|
+
)) {
|
|
1048
|
+
return `${offer.offering}-${offer.chainId.toString()}-${"sell_erc20_callback" /* SellERC20Callback */}-${mempool.Offer.termId(offer)}-${offer.hash}`.toLowerCase();
|
|
1049
|
+
}
|
|
1050
|
+
return null;
|
|
1051
|
+
}
|
|
1052
|
+
function decodeSellERC20CallbackData(data) {
|
|
1053
|
+
if (!data || data === "0x") throw new Error("Empty callback data");
|
|
1054
|
+
try {
|
|
1055
|
+
const [collaterals, amounts] = viem.decodeAbiParameters(
|
|
1056
|
+
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
1057
|
+
data
|
|
1058
|
+
);
|
|
1059
|
+
if (collaterals.length !== amounts.length) {
|
|
1060
|
+
throw new Error("Mismatched array lengths");
|
|
1061
|
+
}
|
|
1062
|
+
return collaterals.map((c, i) => ({ collateral: c, amount: amounts[i] }));
|
|
1063
|
+
} catch (_) {
|
|
1064
|
+
throw new Error("Invalid SellERC20Callback callback data");
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
function decode2(parameters) {
|
|
1068
|
+
const { type, data } = parameters;
|
|
1069
|
+
if (type === "sell_erc20_callback" /* SellERC20Callback */) {
|
|
1070
|
+
return decodeSellERC20CallbackData(data);
|
|
1071
|
+
}
|
|
1072
|
+
throw new Error(`CallbackType not implemented: ${type}`);
|
|
1073
|
+
}
|
|
1074
|
+
function encode2(parameters) {
|
|
1075
|
+
const { type, data } = parameters;
|
|
1076
|
+
if (type === "sell_erc20_callback" /* SellERC20Callback */) {
|
|
1077
|
+
return viem.encodeAbiParameters(
|
|
1078
|
+
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
1079
|
+
[data.collaterals, data.amounts]
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
throw new Error(`CallbackType not implemented: ${type}`);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// src/core/Liquidity.ts
|
|
1086
|
+
var Liquidity_exports = {};
|
|
1087
|
+
__export(Liquidity_exports, {
|
|
1088
|
+
create: () => create,
|
|
1089
|
+
serialize: () => serialize
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
// src/core/Abi.ts
|
|
1093
|
+
var Oracle = [
|
|
1094
|
+
{
|
|
1095
|
+
type: "function",
|
|
1096
|
+
name: "price",
|
|
1097
|
+
inputs: [],
|
|
1098
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
1099
|
+
stateMutability: "view"
|
|
1100
|
+
}
|
|
1101
|
+
];
|
|
1102
|
+
var Morpho = [
|
|
1103
|
+
{
|
|
1104
|
+
type: "function",
|
|
1105
|
+
name: "collateralOf",
|
|
1106
|
+
inputs: [
|
|
1107
|
+
{
|
|
1108
|
+
name: "",
|
|
1109
|
+
type: "address",
|
|
1110
|
+
internalType: "address"
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
name: "",
|
|
1114
|
+
type: "bytes32",
|
|
1115
|
+
internalType: "bytes32"
|
|
1116
|
+
},
|
|
1117
|
+
{
|
|
1118
|
+
name: "",
|
|
1119
|
+
type: "address",
|
|
1120
|
+
internalType: "address"
|
|
1121
|
+
}
|
|
1122
|
+
],
|
|
1123
|
+
outputs: [
|
|
1124
|
+
{
|
|
1125
|
+
name: "",
|
|
1126
|
+
type: "uint256",
|
|
1127
|
+
internalType: "uint256"
|
|
1128
|
+
}
|
|
1129
|
+
],
|
|
1130
|
+
stateMutability: "view"
|
|
1131
|
+
},
|
|
1132
|
+
{
|
|
1133
|
+
type: "function",
|
|
1134
|
+
name: "debtOf",
|
|
1135
|
+
inputs: [
|
|
1136
|
+
{
|
|
1137
|
+
name: "",
|
|
1138
|
+
type: "address",
|
|
1139
|
+
internalType: "address"
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
name: "",
|
|
1143
|
+
type: "bytes32",
|
|
1144
|
+
internalType: "bytes32"
|
|
1145
|
+
}
|
|
1146
|
+
],
|
|
1147
|
+
outputs: [
|
|
1148
|
+
{
|
|
1149
|
+
name: "",
|
|
1150
|
+
type: "uint256",
|
|
1151
|
+
internalType: "uint256"
|
|
1152
|
+
}
|
|
1153
|
+
],
|
|
1154
|
+
stateMutability: "view"
|
|
1155
|
+
}
|
|
1156
|
+
];
|
|
1157
|
+
|
|
1158
|
+
// src/core/Fetchers.ts
|
|
1159
|
+
async function fetchBalancesAndAllowances(parameters) {
|
|
1160
|
+
const { client, spender, pairs, options } = parameters;
|
|
1161
|
+
if (pairs.length === 0) return /* @__PURE__ */ new Map();
|
|
1162
|
+
const batchSize = Math.max(1, options?.batchSize ?? 5e3);
|
|
1163
|
+
const retryAttempts = Math.max(1, options?.retryAttempts ?? 3);
|
|
1164
|
+
const retryDelayMs = Math.max(0, options?.retryDelayMs ?? 50);
|
|
1165
|
+
const blockNumber = options?.blockNumber ? BigInt(options.blockNumber) : void 0;
|
|
1166
|
+
const out = /* @__PURE__ */ new Map();
|
|
1167
|
+
for (const pairsBatch of mempool.Utils.batch(pairs, batchSize)) {
|
|
1168
|
+
const balanceCalls = [];
|
|
1169
|
+
const allowanceCalls = [];
|
|
1170
|
+
for (const { user, token } of pairsBatch) {
|
|
1171
|
+
balanceCalls.push({
|
|
1172
|
+
address: token,
|
|
1173
|
+
abi: viem.erc20Abi,
|
|
1174
|
+
functionName: "balanceOf",
|
|
1175
|
+
args: [user]
|
|
1176
|
+
});
|
|
1177
|
+
allowanceCalls.push({
|
|
1178
|
+
address: token,
|
|
1179
|
+
abi: viem.erc20Abi,
|
|
1180
|
+
functionName: "allowance",
|
|
1181
|
+
args: [user, spender]
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
const [balances, allowances] = await Promise.all([
|
|
1185
|
+
mempool.Utils.retry(
|
|
1186
|
+
() => client.multicall({
|
|
1187
|
+
allowFailure: false,
|
|
1188
|
+
contracts: balanceCalls,
|
|
1189
|
+
...blockNumber ? { blockNumber } : {}
|
|
1190
|
+
}),
|
|
1191
|
+
retryAttempts,
|
|
1192
|
+
retryDelayMs
|
|
1193
|
+
),
|
|
1194
|
+
mempool.Utils.retry(
|
|
1195
|
+
() => client.multicall({
|
|
1196
|
+
allowFailure: false,
|
|
1197
|
+
contracts: allowanceCalls,
|
|
1198
|
+
...blockNumber ? { blockNumber } : {}
|
|
1199
|
+
}),
|
|
1200
|
+
retryAttempts,
|
|
1201
|
+
retryDelayMs
|
|
1202
|
+
)
|
|
1203
|
+
]);
|
|
1204
|
+
for (let i = 0; i < pairsBatch.length; i++) {
|
|
1205
|
+
const { user, token } = pairsBatch[i];
|
|
1206
|
+
const balance = balances[i];
|
|
1207
|
+
const allowance = allowances[i];
|
|
1208
|
+
let perUser = out.get(user);
|
|
1209
|
+
if (!perUser) {
|
|
1210
|
+
perUser = /* @__PURE__ */ new Map();
|
|
1211
|
+
out.set(user, perUser);
|
|
1212
|
+
}
|
|
1213
|
+
perUser.set(token, { balance, allowance });
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return out;
|
|
1092
1217
|
}
|
|
1093
|
-
async function
|
|
1094
|
-
const
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
if (parameters.limit !== void 0) {
|
|
1126
|
-
url.searchParams.set("limit", parameters.limit.toString());
|
|
1218
|
+
async function fetchOraclePrices(parameters) {
|
|
1219
|
+
const { client, oracles, options } = parameters;
|
|
1220
|
+
if (oracles.length === 0) return /* @__PURE__ */ new Map();
|
|
1221
|
+
const batchSize = Math.max(1, options?.batchSize ?? 5e3);
|
|
1222
|
+
const retryAttempts = Math.max(1, options?.retryAttempts ?? 3);
|
|
1223
|
+
const retryDelayMs = Math.max(0, options?.retryDelayMs ?? 50);
|
|
1224
|
+
const blockNumber = options?.blockNumber ? BigInt(options.blockNumber) : void 0;
|
|
1225
|
+
const out = /* @__PURE__ */ new Map();
|
|
1226
|
+
for (const oraclesBatch of mempool.Utils.batch(oracles, batchSize)) {
|
|
1227
|
+
const priceCalls = [];
|
|
1228
|
+
for (const oracle of oraclesBatch) {
|
|
1229
|
+
priceCalls.push({
|
|
1230
|
+
address: oracle,
|
|
1231
|
+
abi: Oracle,
|
|
1232
|
+
functionName: "price",
|
|
1233
|
+
args: []
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
const prices = await mempool.Utils.retry(
|
|
1237
|
+
() => client.multicall({
|
|
1238
|
+
allowFailure: false,
|
|
1239
|
+
contracts: priceCalls,
|
|
1240
|
+
...blockNumber ? { blockNumber } : {}
|
|
1241
|
+
}),
|
|
1242
|
+
retryAttempts,
|
|
1243
|
+
retryDelayMs
|
|
1244
|
+
);
|
|
1245
|
+
for (let i = 0; i < oraclesBatch.length; i++) {
|
|
1246
|
+
const oracle = oraclesBatch[i];
|
|
1247
|
+
const price = prices[i];
|
|
1248
|
+
out.set(oracle, price);
|
|
1249
|
+
}
|
|
1127
1250
|
}
|
|
1128
|
-
|
|
1129
|
-
const routerOffers = offers.map(mempool.Format.fromSnakeCase).map(fromResponse);
|
|
1130
|
-
return {
|
|
1131
|
-
cursor: returnedCursor,
|
|
1132
|
-
offers: routerOffers.map(from).map(toResponse)
|
|
1133
|
-
};
|
|
1251
|
+
return out;
|
|
1134
1252
|
}
|
|
1135
|
-
async function
|
|
1136
|
-
const
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1253
|
+
async function fetchCollateralAndDebt(parameters) {
|
|
1254
|
+
const { client, morphoAddress, queries, options } = parameters;
|
|
1255
|
+
if (queries.length === 0) return /* @__PURE__ */ new Map();
|
|
1256
|
+
const batchSize = Math.max(1, options?.batchSize ?? 5e3);
|
|
1257
|
+
const retryAttempts = Math.max(1, options?.retryAttempts ?? 3);
|
|
1258
|
+
const retryDelayMs = Math.max(0, options?.retryDelayMs ?? 50);
|
|
1259
|
+
const blockNumber = options?.blockNumber ? BigInt(options.blockNumber) : void 0;
|
|
1260
|
+
const out = /* @__PURE__ */ new Map();
|
|
1261
|
+
for (const queriesBatch of mempool.Utils.batch(queries, batchSize)) {
|
|
1262
|
+
const collateralCalls = [];
|
|
1263
|
+
const debtCalls = [];
|
|
1264
|
+
for (const { user, termId, collateralAssets } of queriesBatch) {
|
|
1265
|
+
debtCalls.push({
|
|
1266
|
+
address: morphoAddress,
|
|
1267
|
+
abi: Morpho,
|
|
1268
|
+
functionName: "debtOf",
|
|
1269
|
+
args: [user, termId]
|
|
1148
1270
|
});
|
|
1271
|
+
for (const collateralAsset of collateralAssets) {
|
|
1272
|
+
collateralCalls.push({
|
|
1273
|
+
address: morphoAddress,
|
|
1274
|
+
abi: Morpho,
|
|
1275
|
+
functionName: "collateralOf",
|
|
1276
|
+
args: [user, termId, collateralAsset]
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
const [collateralResults, debtResults] = await Promise.all([
|
|
1281
|
+
mempool.Utils.retry(
|
|
1282
|
+
() => client.multicall({
|
|
1283
|
+
allowFailure: false,
|
|
1284
|
+
contracts: collateralCalls,
|
|
1285
|
+
...blockNumber ? { blockNumber } : {}
|
|
1286
|
+
}),
|
|
1287
|
+
retryAttempts,
|
|
1288
|
+
retryDelayMs
|
|
1289
|
+
),
|
|
1290
|
+
mempool.Utils.retry(
|
|
1291
|
+
() => client.multicall({
|
|
1292
|
+
allowFailure: false,
|
|
1293
|
+
contracts: debtCalls,
|
|
1294
|
+
...blockNumber ? { blockNumber } : {}
|
|
1295
|
+
}),
|
|
1296
|
+
retryAttempts,
|
|
1297
|
+
retryDelayMs
|
|
1298
|
+
)
|
|
1299
|
+
]);
|
|
1300
|
+
let collateralIndex = 0;
|
|
1301
|
+
for (let queryIndex = 0; queryIndex < queriesBatch.length; queryIndex++) {
|
|
1302
|
+
const { user, termId, collateralAssets } = queriesBatch[queryIndex];
|
|
1303
|
+
const debt = debtResults[queryIndex];
|
|
1304
|
+
const collateralByAsset = /* @__PURE__ */ new Map();
|
|
1305
|
+
for (const collateralAsset of collateralAssets) {
|
|
1306
|
+
const collateralAmount = collateralResults[collateralIndex];
|
|
1307
|
+
collateralByAsset.set(collateralAsset.toLowerCase(), collateralAmount);
|
|
1308
|
+
collateralIndex++;
|
|
1309
|
+
}
|
|
1310
|
+
let perUser = out.get(user);
|
|
1311
|
+
if (!perUser) {
|
|
1312
|
+
perUser = /* @__PURE__ */ new Map();
|
|
1313
|
+
out.set(user, perUser);
|
|
1314
|
+
}
|
|
1315
|
+
perUser.set(termId, {
|
|
1316
|
+
collateralByAsset,
|
|
1317
|
+
debt
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1149
1320
|
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1321
|
+
return out;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// src/core/Liquidity.ts
|
|
1325
|
+
async function fetchMaxBorrowCapacity(parameters) {
|
|
1326
|
+
const { client, collaterals, existingDebt, options } = parameters;
|
|
1327
|
+
if (collaterals.length === 0) return 0n;
|
|
1328
|
+
const uniqueOracles = [...new Set(collaterals.map((c) => c.oracle))];
|
|
1329
|
+
const oraclePrices = await fetchOraclePrices({
|
|
1330
|
+
client,
|
|
1331
|
+
oracles: uniqueOracles,
|
|
1332
|
+
options
|
|
1159
1333
|
});
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1334
|
+
const ORACLE_PRICE_SCALE = 10n ** 36n;
|
|
1335
|
+
const PRECISION = 10n ** 18n;
|
|
1336
|
+
let maxDebt = 0n;
|
|
1337
|
+
for (const collateral of collaterals) {
|
|
1338
|
+
const price = oraclePrices.get(collateral.oracle);
|
|
1339
|
+
if (!price) continue;
|
|
1340
|
+
const collateralQuoted = collateral.totalAmount * price / ORACLE_PRICE_SCALE;
|
|
1341
|
+
const collateralMaxDebt = collateralQuoted * collateral.lltv / PRECISION;
|
|
1342
|
+
maxDebt = maxDebt + collateralMaxDebt;
|
|
1343
|
+
}
|
|
1344
|
+
if (existingDebt > 0n) {
|
|
1345
|
+
if (maxDebt > existingDebt) {
|
|
1346
|
+
maxDebt = maxDebt - existingDebt;
|
|
1347
|
+
} else {
|
|
1348
|
+
maxDebt = 0n;
|
|
1168
1349
|
}
|
|
1169
|
-
throw new HttpGetOffersFailedError(`GET request returned ${response.status}`, {
|
|
1170
|
-
details: await response.text()
|
|
1171
|
-
});
|
|
1172
1350
|
}
|
|
1173
|
-
return
|
|
1351
|
+
return maxDebt;
|
|
1174
1352
|
}
|
|
1175
|
-
var
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1353
|
+
var create = (config) => {
|
|
1354
|
+
const { client } = config;
|
|
1355
|
+
return {
|
|
1356
|
+
fetchBuyLiquidity: (parameters) => fetchBuyLiquidity({ ...parameters, client }),
|
|
1357
|
+
fetchSellLiquidity: (parameters) => fetchSellLiquidity({ ...parameters, client })
|
|
1358
|
+
};
|
|
1180
1359
|
};
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1360
|
+
async function fetchBuyLiquidity(parameters) {
|
|
1361
|
+
const { client, chainId, spender, pairs, options } = parameters;
|
|
1362
|
+
const map = await fetchBalancesAndAllowances({
|
|
1363
|
+
client,
|
|
1364
|
+
spender,
|
|
1365
|
+
pairs: pairs.map(({ user, loanToken }) => ({ user, token: loanToken })),
|
|
1366
|
+
options
|
|
1367
|
+
});
|
|
1368
|
+
const out = [];
|
|
1369
|
+
for (const [user, perLoanToken] of map) {
|
|
1370
|
+
for (const [loanToken, { balance, allowance }] of perLoanToken) {
|
|
1371
|
+
const amount = balance < allowance ? balance : allowance;
|
|
1372
|
+
out.push(
|
|
1373
|
+
buildLiquidity({
|
|
1374
|
+
type: "buy_with_empty_callback" /* BuyWithEmptyCallback */,
|
|
1375
|
+
user,
|
|
1376
|
+
loanToken,
|
|
1377
|
+
chainId,
|
|
1378
|
+
amount,
|
|
1379
|
+
index: 0
|
|
1380
|
+
})
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1187
1383
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1384
|
+
return out;
|
|
1385
|
+
}
|
|
1386
|
+
async function fetchSellLiquidity(parameters) {
|
|
1387
|
+
const { client, chainId, spender, morphoAddress, offers, options } = parameters;
|
|
1388
|
+
const collateralPairs = [];
|
|
1389
|
+
for (const offer of offers) {
|
|
1390
|
+
const user = offer.offering;
|
|
1391
|
+
const callbackData = decode2({
|
|
1392
|
+
type: "sell_erc20_callback" /* SellERC20Callback */,
|
|
1393
|
+
data: offer.callback.data
|
|
1193
1394
|
});
|
|
1194
|
-
|
|
1395
|
+
for (const { collateral } of callbackData) {
|
|
1396
|
+
collateralPairs.push({ user, token: collateral });
|
|
1397
|
+
}
|
|
1195
1398
|
}
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1399
|
+
const map = await fetchBalancesAndAllowances({
|
|
1400
|
+
client,
|
|
1401
|
+
spender,
|
|
1402
|
+
pairs: collateralPairs,
|
|
1403
|
+
options
|
|
1404
|
+
});
|
|
1405
|
+
const collateralDebt = [];
|
|
1406
|
+
for (const offer of offers) {
|
|
1407
|
+
const user = offer.offering;
|
|
1408
|
+
const termId = mempool.Offer.termId(offer);
|
|
1409
|
+
const collateralAssets = offer.collaterals.map((collateral) => collateral.asset);
|
|
1410
|
+
collateralDebt.push({
|
|
1411
|
+
user,
|
|
1412
|
+
termId,
|
|
1413
|
+
collateralAssets
|
|
1203
1414
|
});
|
|
1204
|
-
__publicField(this, "name", "Router.HttpRateLimitError");
|
|
1205
1415
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1416
|
+
const existingPositions = await fetchCollateralAndDebt({
|
|
1417
|
+
client,
|
|
1418
|
+
morphoAddress,
|
|
1419
|
+
queries: collateralDebt,
|
|
1420
|
+
options
|
|
1421
|
+
});
|
|
1422
|
+
const out = [];
|
|
1423
|
+
for (const offer of offers) {
|
|
1424
|
+
const user = offer.offering;
|
|
1425
|
+
const termId = mempool.Offer.termId(offer);
|
|
1426
|
+
const callbackData = decode2({
|
|
1427
|
+
type: "sell_erc20_callback" /* SellERC20Callback */,
|
|
1428
|
+
data: offer.callback.data
|
|
1211
1429
|
});
|
|
1212
|
-
|
|
1430
|
+
const callbackCollaterals = callbackData.map((callbackItem) => {
|
|
1431
|
+
const userMap = map.get(user);
|
|
1432
|
+
const tokenData = userMap?.get(callbackItem.collateral);
|
|
1433
|
+
if (!tokenData) return null;
|
|
1434
|
+
const offerCollateral = offer.collaterals.find(
|
|
1435
|
+
(c) => c.asset.toLowerCase() === callbackItem.collateral.toLowerCase()
|
|
1436
|
+
);
|
|
1437
|
+
if (!offerCollateral) return null;
|
|
1438
|
+
const { balance, allowance } = tokenData;
|
|
1439
|
+
const availableAmount = balance < allowance ? balance : allowance;
|
|
1440
|
+
return {
|
|
1441
|
+
collateralAddress: callbackItem.collateral,
|
|
1442
|
+
balance: availableAmount,
|
|
1443
|
+
callbackAmount: callbackItem.amount
|
|
1444
|
+
};
|
|
1445
|
+
}).filter((collateral) => collateral !== null);
|
|
1446
|
+
if (callbackCollaterals.length === 0) continue;
|
|
1447
|
+
const existingPosition = existingPositions.get(user)?.get(termId);
|
|
1448
|
+
const collaterals = offer.collaterals.map((c) => {
|
|
1449
|
+
const callbackCollateral = callbackCollaterals.find(
|
|
1450
|
+
(cc) => cc.collateralAddress.toLowerCase() === c.asset.toLowerCase()
|
|
1451
|
+
);
|
|
1452
|
+
const callbackAmount = callbackCollateral?.balance ?? 0n;
|
|
1453
|
+
const existingAmount = existingPosition?.collateralByAsset.get(c.asset.toLowerCase()) ?? 0n;
|
|
1454
|
+
return {
|
|
1455
|
+
asset: c.asset,
|
|
1456
|
+
oracle: c.oracle,
|
|
1457
|
+
lltv: c.lltv,
|
|
1458
|
+
totalAmount: existingAmount + callbackAmount
|
|
1459
|
+
};
|
|
1460
|
+
});
|
|
1461
|
+
const existingDebt = existingPosition?.debt ?? 0n;
|
|
1462
|
+
const userPositionAmount = await fetchMaxBorrowCapacity({
|
|
1463
|
+
client,
|
|
1464
|
+
collaterals,
|
|
1465
|
+
existingDebt,
|
|
1466
|
+
options
|
|
1467
|
+
});
|
|
1468
|
+
out.push(
|
|
1469
|
+
buildLiquidity({
|
|
1470
|
+
type: "sell_erc20_callback" /* SellERC20Callback */,
|
|
1471
|
+
user,
|
|
1472
|
+
termId,
|
|
1473
|
+
offerHash: offer.hash,
|
|
1474
|
+
chainId,
|
|
1475
|
+
amount: userPositionAmount,
|
|
1476
|
+
collaterals: callbackCollaterals,
|
|
1477
|
+
index: 0
|
|
1478
|
+
})
|
|
1479
|
+
);
|
|
1213
1480
|
}
|
|
1214
|
-
|
|
1481
|
+
return out;
|
|
1482
|
+
}
|
|
1483
|
+
function serialize(liquidity) {
|
|
1484
|
+
const normalized = {
|
|
1485
|
+
userPosition: {
|
|
1486
|
+
id: liquidity.userPosition.id,
|
|
1487
|
+
availableLiquidityQueueId: liquidity.userPosition.availableLiquidityQueueId,
|
|
1488
|
+
user: liquidity.userPosition.user,
|
|
1489
|
+
chainId: String(liquidity.userPosition.chainId),
|
|
1490
|
+
amount: String(liquidity.userPosition.amount)
|
|
1491
|
+
},
|
|
1492
|
+
queues: liquidity.queues.map((queueWithPool) => ({
|
|
1493
|
+
queue: {
|
|
1494
|
+
queueId: queueWithPool.queue.queueId,
|
|
1495
|
+
availableLiquidityPoolId: queueWithPool.queue.availableLiquidityPoolId,
|
|
1496
|
+
index: queueWithPool.queue.index
|
|
1497
|
+
},
|
|
1498
|
+
pool: {
|
|
1499
|
+
id: queueWithPool.pool.id,
|
|
1500
|
+
amount: String(queueWithPool.pool.amount)
|
|
1501
|
+
}
|
|
1502
|
+
})).sort(
|
|
1503
|
+
(left, right) => {
|
|
1504
|
+
const leftQueueId = left.queue.queueId || "";
|
|
1505
|
+
const rightQueueId = right.queue.queueId || "";
|
|
1506
|
+
if (leftQueueId < rightQueueId) return -1;
|
|
1507
|
+
if (leftQueueId > rightQueueId) return 1;
|
|
1508
|
+
const leftPoolId = left.pool.id;
|
|
1509
|
+
const rightPoolId = right.pool.id;
|
|
1510
|
+
if (leftPoolId < rightPoolId) return -1;
|
|
1511
|
+
if (leftPoolId > rightPoolId) return 1;
|
|
1512
|
+
const leftIndex = left.queue.index;
|
|
1513
|
+
const rightIndex = right.queue.index;
|
|
1514
|
+
if (leftIndex < rightIndex) return -1;
|
|
1515
|
+
if (leftIndex > rightIndex) return 1;
|
|
1516
|
+
return 0;
|
|
1517
|
+
}
|
|
1518
|
+
)
|
|
1519
|
+
};
|
|
1520
|
+
return JSON.stringify(normalized);
|
|
1521
|
+
}
|
|
1215
1522
|
|
|
1216
1523
|
// src/core/Validation.ts
|
|
1217
1524
|
var Validation_exports = {};
|
|
@@ -1317,7 +1624,7 @@ function morpho() {
|
|
|
1317
1624
|
(offer, _) => {
|
|
1318
1625
|
if (!offer.buy && offer.callback.data !== "0x") {
|
|
1319
1626
|
const allowed = new Set(
|
|
1320
|
-
WhitelistedCallbackAddresses["
|
|
1627
|
+
WhitelistedCallbackAddresses["sell_erc20_callback" /* SellERC20Callback */].map(
|
|
1321
1628
|
(a) => a.toLowerCase()
|
|
1322
1629
|
)
|
|
1323
1630
|
);
|
|
@@ -1333,8 +1640,8 @@ function morpho() {
|
|
|
1333
1640
|
(offer, _) => {
|
|
1334
1641
|
if (!offer.buy && offer.callback.data !== "0x") {
|
|
1335
1642
|
try {
|
|
1336
|
-
const decoded =
|
|
1337
|
-
type: "
|
|
1643
|
+
const decoded = decode2({
|
|
1644
|
+
type: "sell_erc20_callback" /* SellERC20Callback */,
|
|
1338
1645
|
data: offer.callback.data
|
|
1339
1646
|
});
|
|
1340
1647
|
if (decoded.length === 0) {
|
|
@@ -1351,8 +1658,8 @@ function morpho() {
|
|
|
1351
1658
|
(offer, _) => {
|
|
1352
1659
|
if (!offer.buy && offer.callback.data !== "0x") {
|
|
1353
1660
|
try {
|
|
1354
|
-
const decoded =
|
|
1355
|
-
type: "
|
|
1661
|
+
const decoded = decode2({
|
|
1662
|
+
type: "sell_erc20_callback" /* SellERC20Callback */,
|
|
1356
1663
|
data: offer.callback.data
|
|
1357
1664
|
});
|
|
1358
1665
|
const offerCollaterals = new Set(
|
|
@@ -1368,10 +1675,19 @@ function morpho() {
|
|
|
1368
1675
|
}
|
|
1369
1676
|
}
|
|
1370
1677
|
);
|
|
1678
|
+
const maturity = single("maturity", (offer, _) => {
|
|
1679
|
+
const allowedMaturities = [mempool.Maturity.from("end_of_month"), mempool.Maturity.from("end_of_next_month")];
|
|
1680
|
+
if (!allowedMaturities.includes(offer.maturity)) {
|
|
1681
|
+
return {
|
|
1682
|
+
message: `Maturity must be end of current month (${allowedMaturities[0]}) or end of next month (${allowedMaturities[1]}). Got: ${offer.maturity}`
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
});
|
|
1371
1686
|
return [
|
|
1372
1687
|
chainId,
|
|
1373
1688
|
loanToken,
|
|
1374
1689
|
expiry,
|
|
1690
|
+
maturity,
|
|
1375
1691
|
// note: callback rules should be the last ones, since they do not mean that the offer is forever invalid
|
|
1376
1692
|
// integrators should be able to choose if they want to keep the offer or not
|
|
1377
1693
|
sellEmptyCallback,
|
|
@@ -1385,7 +1701,7 @@ function morpho() {
|
|
|
1385
1701
|
exports.Callback = Callback_exports;
|
|
1386
1702
|
exports.Cursor = Cursor_exports;
|
|
1387
1703
|
exports.Liquidity = Liquidity_exports;
|
|
1388
|
-
exports.
|
|
1704
|
+
exports.RouterApi = Client_exports;
|
|
1389
1705
|
exports.RouterOffer = RouterOffer_exports;
|
|
1390
1706
|
exports.Validation = Validation_exports;
|
|
1391
1707
|
exports.ValidationRule = ValidationRule_exports;
|