@morpho-dev/router 0.1.9 → 0.1.11
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/dist/drizzle/offers_v1.1/0006_add-callback-amount-to-queues-table.sql +1 -0
- package/dist/drizzle/offers_v1.1/0007_add-index-to-created-at.sql +2 -0
- package/dist/drizzle/offers_v1.1/meta/0006_snapshot.json +884 -0
- package/dist/drizzle/offers_v1.1/meta/0007_snapshot.json +932 -0
- package/dist/drizzle/offers_v1.1/meta/_journal.json +14 -0
- package/dist/index.browser.d.cts +140 -12
- package/dist/index.browser.d.ts +140 -12
- package/dist/index.browser.js +211 -47
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +212 -48
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.cts +158 -12
- package/dist/index.node.d.ts +158 -12
- package/dist/index.node.js +347 -121
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +349 -123
- package/dist/index.node.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.browser.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Errors, LLTV,
|
|
1
|
+
import { Errors, LLTV, Offer, Utils, Format } from '@morpho-dev/mempool';
|
|
2
2
|
export * from '@morpho-dev/mempool';
|
|
3
|
+
import { parseUnits, encodeAbiParameters, maxUint256, formatUnits, decodeAbiParameters, erc20Abi } from 'viem';
|
|
3
4
|
import { Base64 } from 'js-base64';
|
|
4
|
-
import { parseUnits, maxUint256, formatUnits, erc20Abi } from 'viem';
|
|
5
5
|
import { z } from 'zod/v4';
|
|
6
6
|
import { createDocument } from 'zod-openapi';
|
|
7
7
|
|
|
@@ -17,60 +17,153 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
|
|
|
17
17
|
var Callback_exports = {};
|
|
18
18
|
__export(Callback_exports, {
|
|
19
19
|
CallbackType: () => CallbackType,
|
|
20
|
+
WhitelistedCallbackAddresses: () => WhitelistedCallbackAddresses,
|
|
20
21
|
buildLiquidity: () => buildLiquidity,
|
|
22
|
+
decode: () => decode,
|
|
23
|
+
encode: () => encode,
|
|
21
24
|
getCallbackIdForOffer: () => getCallbackIdForOffer
|
|
22
25
|
});
|
|
23
26
|
var CallbackType = /* @__PURE__ */ ((CallbackType2) => {
|
|
24
27
|
CallbackType2["BuyWithEmptyCallback"] = "buy_with_empty_callback";
|
|
28
|
+
CallbackType2["SellWithdrawFromWallet"] = "sell_withdraw_from_wallet";
|
|
25
29
|
return CallbackType2;
|
|
26
30
|
})(CallbackType || {});
|
|
31
|
+
var WhitelistedCallbackAddresses = {
|
|
32
|
+
["buy_with_empty_callback" /* BuyWithEmptyCallback */]: [],
|
|
33
|
+
["sell_withdraw_from_wallet" /* SellWithdrawFromWallet */]: [
|
|
34
|
+
"0x1111111111111111111111111111111111111111",
|
|
35
|
+
"0x2222222222222222222222222222222222222222"
|
|
36
|
+
// @TODO: update once deployed and add mapping per chain if needed
|
|
37
|
+
].map((address) => address.toLowerCase())
|
|
38
|
+
};
|
|
27
39
|
function buildLiquidity(parameters) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
},
|
|
42
|
-
queues: [
|
|
43
|
-
{
|
|
44
|
-
queue: {
|
|
45
|
-
queueId: id,
|
|
46
|
-
availableLiquidityPoolId: id,
|
|
47
|
-
index,
|
|
40
|
+
switch (parameters.type) {
|
|
41
|
+
case "buy_with_empty_callback" /* BuyWithEmptyCallback */: {
|
|
42
|
+
const { user, loanToken, chainId, amount, index = 0, updatedAt = /* @__PURE__ */ new Date() } = parameters;
|
|
43
|
+
const amountStr = amount.toString();
|
|
44
|
+
const id = `${user}-${chainId.toString()}-${parameters.type}-${loanToken}`.toLowerCase();
|
|
45
|
+
const poolId = `${user}-${chainId.toString()}-${loanToken}`.toLowerCase();
|
|
46
|
+
return {
|
|
47
|
+
userPosition: {
|
|
48
|
+
id,
|
|
49
|
+
availableLiquidityQueueId: id,
|
|
50
|
+
user: user.toLowerCase(),
|
|
51
|
+
chainId,
|
|
52
|
+
amount: amountStr,
|
|
48
53
|
updatedAt
|
|
49
54
|
},
|
|
50
|
-
|
|
55
|
+
queues: [
|
|
56
|
+
{
|
|
57
|
+
queue: {
|
|
58
|
+
queueId: id,
|
|
59
|
+
availableLiquidityPoolId: poolId,
|
|
60
|
+
index,
|
|
61
|
+
callbackAmount: "0",
|
|
62
|
+
updatedAt
|
|
63
|
+
},
|
|
64
|
+
pool: {
|
|
65
|
+
id: poolId,
|
|
66
|
+
amount: amountStr,
|
|
67
|
+
updatedAt
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
case "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */: {
|
|
74
|
+
const {
|
|
75
|
+
user,
|
|
76
|
+
termId,
|
|
77
|
+
chainId,
|
|
78
|
+
amount,
|
|
79
|
+
collaterals,
|
|
80
|
+
index = 0,
|
|
81
|
+
updatedAt = /* @__PURE__ */ new Date()
|
|
82
|
+
} = parameters;
|
|
83
|
+
const amountStr = amount.toString();
|
|
84
|
+
const id = `${user}-${chainId.toString()}-${parameters.type}-${termId}`.toLowerCase();
|
|
85
|
+
return {
|
|
86
|
+
userPosition: {
|
|
51
87
|
id,
|
|
88
|
+
availableLiquidityQueueId: id,
|
|
89
|
+
user: user.toLowerCase(),
|
|
90
|
+
chainId,
|
|
52
91
|
amount: amountStr,
|
|
53
92
|
updatedAt
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
93
|
+
},
|
|
94
|
+
queues: collaterals.map((collateral) => {
|
|
95
|
+
const poolId = `${user}-${chainId.toString()}-${collateral.collateralAddress}`.toLowerCase();
|
|
96
|
+
return {
|
|
97
|
+
queue: {
|
|
98
|
+
queueId: id,
|
|
99
|
+
availableLiquidityPoolId: poolId,
|
|
100
|
+
index,
|
|
101
|
+
callbackAmount: collateral.callbackAmount.toString(),
|
|
102
|
+
updatedAt
|
|
103
|
+
},
|
|
104
|
+
pool: {
|
|
105
|
+
id: poolId,
|
|
106
|
+
amount: collateral.balance.toString(),
|
|
107
|
+
updatedAt
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
})
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
default: {
|
|
114
|
+
throw new Error(`CallbackType not implemented`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
58
117
|
}
|
|
59
118
|
function getCallbackIdForOffer(offer) {
|
|
60
119
|
if (offer.buy && offer.callback.data === "0x") {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
120
|
+
return `${offer.offering}-${offer.chainId.toString()}-${"buy_with_empty_callback" /* BuyWithEmptyCallback */}-${offer.loanToken}`.toLowerCase();
|
|
121
|
+
}
|
|
122
|
+
if (!offer.buy && offer.callback.data !== "0x" && WhitelistedCallbackAddresses["sell_withdraw_from_wallet" /* SellWithdrawFromWallet */].includes(
|
|
123
|
+
offer.callback.address.toLowerCase()
|
|
124
|
+
)) {
|
|
125
|
+
return `${offer.offering}-${offer.chainId.toString()}-${"sell_withdraw_from_wallet" /* SellWithdrawFromWallet */}-${Offer.termId(offer)}`.toLowerCase();
|
|
65
126
|
}
|
|
66
127
|
return null;
|
|
67
128
|
}
|
|
129
|
+
function decodeSellWithdrawFromWalletData(data) {
|
|
130
|
+
if (!data || data === "0x") throw new Error("Empty callback data");
|
|
131
|
+
try {
|
|
132
|
+
const [collaterals, amounts] = decodeAbiParameters(
|
|
133
|
+
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
134
|
+
data
|
|
135
|
+
);
|
|
136
|
+
if (collaterals.length !== amounts.length) {
|
|
137
|
+
throw new Error("Mismatched array lengths");
|
|
138
|
+
}
|
|
139
|
+
return collaterals.map((c, i) => ({ collateral: c, amount: amounts[i] }));
|
|
140
|
+
} catch (_) {
|
|
141
|
+
throw new Error("Invalid SellWithdrawFromWallet callback data");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function decode(parameters) {
|
|
145
|
+
const { type, data } = parameters;
|
|
146
|
+
if (type === "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */) {
|
|
147
|
+
return decodeSellWithdrawFromWalletData(data);
|
|
148
|
+
}
|
|
149
|
+
throw new Error(`CallbackType not implemented: ${type}`);
|
|
150
|
+
}
|
|
151
|
+
function encode(parameters) {
|
|
152
|
+
const { type, data } = parameters;
|
|
153
|
+
if (type === "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */) {
|
|
154
|
+
return encodeAbiParameters(
|
|
155
|
+
[{ type: "address[]" }, { type: "uint256[]" }],
|
|
156
|
+
[data.collaterals, data.amounts]
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
throw new Error(`CallbackType not implemented: ${type}`);
|
|
160
|
+
}
|
|
68
161
|
|
|
69
162
|
// src/core/Cursor.ts
|
|
70
163
|
var Cursor_exports = {};
|
|
71
164
|
__export(Cursor_exports, {
|
|
72
|
-
decode: () =>
|
|
73
|
-
encode: () =>
|
|
165
|
+
decode: () => decode2,
|
|
166
|
+
encode: () => encode2,
|
|
74
167
|
validate: () => validate
|
|
75
168
|
});
|
|
76
169
|
function validate(cursor) {
|
|
@@ -142,10 +235,10 @@ function validate(cursor) {
|
|
|
142
235
|
}
|
|
143
236
|
return true;
|
|
144
237
|
}
|
|
145
|
-
function
|
|
238
|
+
function encode2(c) {
|
|
146
239
|
return Base64.encodeURL(JSON.stringify(c));
|
|
147
240
|
}
|
|
148
|
-
function
|
|
241
|
+
function decode2(token) {
|
|
149
242
|
if (!token) return null;
|
|
150
243
|
const decoded = JSON.parse(Base64.decode(token));
|
|
151
244
|
validate(decoded);
|
|
@@ -225,20 +318,20 @@ async function fetch2(parameters) {
|
|
|
225
318
|
const map = await fetchBalancesAndAllowances({
|
|
226
319
|
client,
|
|
227
320
|
spender,
|
|
228
|
-
pairs: pairs.map(({ user,
|
|
321
|
+
pairs: pairs.map(({ user, loanToken }) => ({ user, token: loanToken })),
|
|
229
322
|
options
|
|
230
323
|
});
|
|
231
324
|
const out = [];
|
|
232
|
-
for (const [user,
|
|
233
|
-
for (const [
|
|
325
|
+
for (const [user, perLoanToken] of map) {
|
|
326
|
+
for (const [loanToken, { balance, allowance }] of perLoanToken) {
|
|
234
327
|
const amount = balance < allowance ? balance : allowance;
|
|
235
328
|
out.push(
|
|
236
329
|
buildLiquidity({
|
|
237
330
|
type,
|
|
238
331
|
user,
|
|
239
|
-
|
|
332
|
+
loanToken,
|
|
240
333
|
chainId,
|
|
241
|
-
amount
|
|
334
|
+
amount,
|
|
242
335
|
index: 0
|
|
243
336
|
})
|
|
244
337
|
);
|
|
@@ -554,7 +647,7 @@ var GetOffersQueryParams = z.object({
|
|
|
554
647
|
(val) => {
|
|
555
648
|
if (!val) return true;
|
|
556
649
|
try {
|
|
557
|
-
const decoded =
|
|
650
|
+
const decoded = decode2(val);
|
|
558
651
|
return decoded !== null;
|
|
559
652
|
} catch (_error) {
|
|
560
653
|
return false;
|
|
@@ -726,7 +819,7 @@ var MatchOffersQueryParams = z.object({
|
|
|
726
819
|
(val) => {
|
|
727
820
|
if (!val) return true;
|
|
728
821
|
try {
|
|
729
|
-
const decoded =
|
|
822
|
+
const decoded = decode2(val);
|
|
730
823
|
return decoded !== null;
|
|
731
824
|
} catch (_error) {
|
|
732
825
|
return false;
|
|
@@ -1202,18 +1295,89 @@ function morpho() {
|
|
|
1202
1295
|
return { message: "Expiry mismatch" };
|
|
1203
1296
|
}
|
|
1204
1297
|
});
|
|
1205
|
-
const
|
|
1206
|
-
|
|
1207
|
-
|
|
1298
|
+
const sellEmptyCallback = single(
|
|
1299
|
+
"sell_offers_empty_callback",
|
|
1300
|
+
(offer, _) => {
|
|
1301
|
+
if (!offer.buy && offer.callback.data === "0x") {
|
|
1302
|
+
return { message: "Sell offers require a non-empty callback." };
|
|
1303
|
+
}
|
|
1208
1304
|
}
|
|
1209
|
-
|
|
1305
|
+
);
|
|
1306
|
+
const buyNonEmptyCallback = single(
|
|
1307
|
+
"buy_offers_non_empty_callback",
|
|
1308
|
+
(offer, _) => {
|
|
1309
|
+
if (offer.buy && offer.callback.data !== "0x") {
|
|
1310
|
+
return { message: "Buy offers must use an empty callback." };
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
);
|
|
1314
|
+
const sellNonWhitelistedCallback = single(
|
|
1315
|
+
"sell_offers_non_whitelisted_callback",
|
|
1316
|
+
(offer, _) => {
|
|
1317
|
+
if (!offer.buy && offer.callback.data !== "0x") {
|
|
1318
|
+
const allowed = new Set(
|
|
1319
|
+
WhitelistedCallbackAddresses["sell_withdraw_from_wallet" /* SellWithdrawFromWallet */].map(
|
|
1320
|
+
(a) => a.toLowerCase()
|
|
1321
|
+
)
|
|
1322
|
+
);
|
|
1323
|
+
const callbackAddress = offer.callback.address?.toLowerCase();
|
|
1324
|
+
if (!callbackAddress || !allowed.has(callbackAddress)) {
|
|
1325
|
+
return { message: "Sell offer callback address is not whitelisted." };
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
);
|
|
1330
|
+
const sellCallbackDataInvalid = single(
|
|
1331
|
+
"sell_offers_callback_data_invalid",
|
|
1332
|
+
(offer, _) => {
|
|
1333
|
+
if (!offer.buy && offer.callback.data !== "0x") {
|
|
1334
|
+
try {
|
|
1335
|
+
const decoded = decode({
|
|
1336
|
+
type: "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */,
|
|
1337
|
+
data: offer.callback.data
|
|
1338
|
+
});
|
|
1339
|
+
if (decoded.length === 0) {
|
|
1340
|
+
return { message: "Sell offer callback data must include at least one collateral." };
|
|
1341
|
+
}
|
|
1342
|
+
} catch (_2) {
|
|
1343
|
+
return { message: "Sell offer callback data cannot be decoded." };
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
);
|
|
1348
|
+
const sellCallbackCollateralInvalid = single(
|
|
1349
|
+
"sell_offers_callback_collateral_invalid",
|
|
1350
|
+
(offer, _) => {
|
|
1351
|
+
if (!offer.buy && offer.callback.data !== "0x") {
|
|
1352
|
+
try {
|
|
1353
|
+
const decoded = decode({
|
|
1354
|
+
type: "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */,
|
|
1355
|
+
data: offer.callback.data
|
|
1356
|
+
});
|
|
1357
|
+
const offerCollaterals = new Set(
|
|
1358
|
+
offer.collaterals.map((c) => c.asset.toLowerCase())
|
|
1359
|
+
);
|
|
1360
|
+
for (const { collateral } of decoded) {
|
|
1361
|
+
if (!offerCollaterals.has(collateral.toLowerCase())) {
|
|
1362
|
+
return { message: "Sell callback collateral is not part of offer collaterals." };
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
} catch (_2) {
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
);
|
|
1210
1370
|
return [
|
|
1211
1371
|
chainId,
|
|
1212
1372
|
loanToken,
|
|
1213
1373
|
expiry,
|
|
1214
|
-
// note: callback
|
|
1374
|
+
// note: callback rules should be the last ones, since they do not mean that the offer is forever invalid
|
|
1215
1375
|
// integrators should be able to choose if they want to keep the offer or not
|
|
1216
|
-
|
|
1376
|
+
sellEmptyCallback,
|
|
1377
|
+
buyNonEmptyCallback,
|
|
1378
|
+
sellNonWhitelistedCallback,
|
|
1379
|
+
sellCallbackDataInvalid,
|
|
1380
|
+
sellCallbackCollateralInvalid
|
|
1217
1381
|
];
|
|
1218
1382
|
}
|
|
1219
1383
|
|