@morpho-dev/router 0.1.17 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/cli.js +204 -53
- package/dist/cli.js.map +1 -1
- package/dist/index.browser.d.cts +26 -4
- package/dist/index.browser.d.ts +26 -4
- package/dist/index.browser.js +93 -24
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +93 -24
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.cts +170 -12
- package/dist/index.node.d.ts +170 -12
- package/dist/index.node.js +245 -24
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +245 -25
- package/dist/index.node.mjs.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -19,17 +19,17 @@ pnpm add -g @morpho-dev/router
|
|
|
19
19
|
Examples:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
# Router with seeded random offers
|
|
23
|
-
router start --seed 100
|
|
24
|
-
|
|
25
22
|
# Router with postgres database and custom port
|
|
26
23
|
router start --db-endpoint <db url> --port 8080
|
|
27
24
|
|
|
28
|
-
# Router with offers loaded from file
|
|
29
|
-
router start --file offers.json
|
|
30
|
-
|
|
31
25
|
# Start Router indexer (Default indexer,api)
|
|
32
26
|
router start --services indexer
|
|
27
|
+
|
|
28
|
+
# Router Mock with seeded random offers
|
|
29
|
+
router mock --seed 100
|
|
30
|
+
|
|
31
|
+
# Router with offers loaded from file
|
|
32
|
+
router mock --file offers.json
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
<!-- AUTO-GENERATED: CLI-HELP START -->
|
package/dist/cli.js
CHANGED
|
@@ -41,7 +41,7 @@ var __export = (target, all) => {
|
|
|
41
41
|
// package.json
|
|
42
42
|
var package_default = {
|
|
43
43
|
name: "@morpho-dev/router",
|
|
44
|
-
version: "0.1.
|
|
44
|
+
version: "0.1.18",
|
|
45
45
|
description: "Router package for Morpho protocol"};
|
|
46
46
|
|
|
47
47
|
// src/core/Chain.ts
|
|
@@ -142,8 +142,12 @@ var chains = {
|
|
|
142
142
|
[
|
|
143
143
|
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
144
144
|
// USDC
|
|
145
|
-
"0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
|
145
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
146
146
|
// DAI
|
|
147
|
+
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
148
|
+
// WETH
|
|
149
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
150
|
+
// WBTC
|
|
147
151
|
].map((address) => address.toLowerCase())
|
|
148
152
|
),
|
|
149
153
|
morpho: "0x0000000000000000000000000000000000000000",
|
|
@@ -166,8 +170,12 @@ var chains = {
|
|
|
166
170
|
[
|
|
167
171
|
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
168
172
|
// USDC
|
|
169
|
-
"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb"
|
|
173
|
+
"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
|
|
170
174
|
// DAI
|
|
175
|
+
"0x4200000000000000000000000000000000000006",
|
|
176
|
+
// WETH
|
|
177
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
178
|
+
// WBTC
|
|
171
179
|
].map((address) => address.toLowerCase())
|
|
172
180
|
),
|
|
173
181
|
morpho: "0x0000000000000000000000000000000000000000",
|
|
@@ -190,8 +198,12 @@ var chains = {
|
|
|
190
198
|
[
|
|
191
199
|
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
192
200
|
// USDC
|
|
193
|
-
"0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
|
201
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
194
202
|
// DAI
|
|
203
|
+
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
204
|
+
// WETH
|
|
205
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
206
|
+
// WBTC
|
|
195
207
|
].map((address) => address.toLowerCase())
|
|
196
208
|
),
|
|
197
209
|
morpho: "0x11a002d45db720ed47a80d2f3489cba5b833eaf5",
|
|
@@ -215,8 +227,12 @@ var chains = {
|
|
|
215
227
|
[
|
|
216
228
|
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
217
229
|
// USDC
|
|
218
|
-
"0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
|
230
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
219
231
|
// DAI
|
|
232
|
+
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
233
|
+
// WETH
|
|
234
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
235
|
+
// WBTC
|
|
220
236
|
].map((address) => address.toLowerCase())
|
|
221
237
|
),
|
|
222
238
|
morpho: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
|
|
@@ -1215,39 +1231,92 @@ function fromSnakeCase3(input) {
|
|
|
1215
1231
|
function toSnakeCase2(offer) {
|
|
1216
1232
|
return toSnakeCase(offer);
|
|
1217
1233
|
}
|
|
1218
|
-
function random2() {
|
|
1219
|
-
const
|
|
1220
|
-
const
|
|
1221
|
-
const
|
|
1222
|
-
const
|
|
1234
|
+
function random2(config) {
|
|
1235
|
+
const chain = config?.chains ? config.chains[Math.floor(Math.random() * config.chains.length)] : chains.ethereum;
|
|
1236
|
+
const loanToken = config?.loanTokens ? config.loanTokens[Math.floor(Math.random() * config.loanTokens.length)] : privateKeyToAccount(generatePrivateKey()).address;
|
|
1237
|
+
const collateralCandidates = config?.collateralTokens ? config.collateralTokens.filter((a) => a !== loanToken) : [privateKeyToAccount(generatePrivateKey()).address];
|
|
1238
|
+
const collateralAsset = collateralCandidates[Math.floor(Math.random() * collateralCandidates.length)];
|
|
1239
|
+
const maturityOption = weightedChoice([
|
|
1240
|
+
["end_of_month", 1],
|
|
1241
|
+
["end_of_next_month", 1]
|
|
1242
|
+
]);
|
|
1243
|
+
const maturity = config?.maturity ?? from3(maturityOption);
|
|
1244
|
+
const lltv = from(
|
|
1245
|
+
weightedChoice([
|
|
1246
|
+
[0.385, 1],
|
|
1247
|
+
[0.5, 1],
|
|
1248
|
+
[0.625, 2],
|
|
1249
|
+
[0.77, 8],
|
|
1250
|
+
[0.86, 10],
|
|
1251
|
+
[0.915, 8],
|
|
1252
|
+
[0.945, 6],
|
|
1253
|
+
[0.965, 4],
|
|
1254
|
+
[0.98, 2]
|
|
1255
|
+
])
|
|
1256
|
+
);
|
|
1257
|
+
const buy = config?.buy !== void 0 ? config.buy : Math.random() > 0.5;
|
|
1258
|
+
const ONE = 1000000000000000000n;
|
|
1259
|
+
const qMin = buy ? 16 : 4;
|
|
1260
|
+
const qMax = buy ? 32 : 16;
|
|
1261
|
+
const len = qMax - qMin + 1;
|
|
1262
|
+
const ratePairs = Array.from(
|
|
1263
|
+
{ length: len },
|
|
1264
|
+
(_, idx) => {
|
|
1265
|
+
const q = qMin + idx;
|
|
1266
|
+
const scaledRate = BigInt(q) * (ONE / 4n);
|
|
1267
|
+
const weight = buy ? 1 + idx : 1 + (len - 1 - idx);
|
|
1268
|
+
return [scaledRate, weight];
|
|
1269
|
+
}
|
|
1270
|
+
);
|
|
1271
|
+
const rate = config?.rate ?? weightedChoice(ratePairs);
|
|
1272
|
+
const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
|
|
1273
|
+
const unit = BigInt(10) ** BigInt(loanTokenDecimals);
|
|
1274
|
+
const amountBase = BigInt(100 + Math.floor(Math.random() * (1e6 - 100 + 1)));
|
|
1275
|
+
const assetsScaled = config?.assets ?? amountBase * unit;
|
|
1276
|
+
const consumed2 = config?.consumed !== void 0 ? config.consumed : Math.random() < 0.8 ? 0n : assetsScaled * BigInt(1 + Math.floor(Math.random() * 900)) / 1000n;
|
|
1277
|
+
const callbackBySide = (() => {
|
|
1278
|
+
if (buy) return { address: zeroAddress, data: "0x", gasLimit: 0n };
|
|
1279
|
+
const sellCallbackAddress = WhitelistedCallbackAddresses["sell_erc20_callback" /* SellERC20Callback */][0].toLowerCase();
|
|
1280
|
+
const amount = assetsScaled * 1000000000000000000000n;
|
|
1281
|
+
const data = encodeSellERC20Callback({
|
|
1282
|
+
collaterals: [collateralAsset],
|
|
1283
|
+
amounts: [amount]
|
|
1284
|
+
});
|
|
1285
|
+
return { address: sellCallbackAddress, data, gasLimit: 500000n };
|
|
1286
|
+
})();
|
|
1223
1287
|
const offer = from5({
|
|
1224
|
-
offering: privateKeyToAccount(generatePrivateKey()).address,
|
|
1225
|
-
assets:
|
|
1226
|
-
rate
|
|
1288
|
+
offering: config?.offering ?? privateKeyToAccount(generatePrivateKey()).address,
|
|
1289
|
+
assets: assetsScaled,
|
|
1290
|
+
rate,
|
|
1227
1291
|
maturity,
|
|
1228
|
-
expiry,
|
|
1229
|
-
start:
|
|
1292
|
+
expiry: config?.expiry ?? maturity - 1,
|
|
1293
|
+
start: config?.start ?? maturity - 10,
|
|
1230
1294
|
nonce: BigInt(Math.floor(Math.random() * 1e6)),
|
|
1231
|
-
buy
|
|
1232
|
-
chainId:
|
|
1295
|
+
buy,
|
|
1296
|
+
chainId: chain.id,
|
|
1233
1297
|
loanToken,
|
|
1234
|
-
collaterals: [
|
|
1298
|
+
collaterals: config?.collaterals ?? [
|
|
1235
1299
|
from2({
|
|
1236
|
-
asset:
|
|
1300
|
+
asset: collateralAsset,
|
|
1237
1301
|
oracle: zeroAddress,
|
|
1238
1302
|
lltv
|
|
1239
1303
|
})
|
|
1240
1304
|
],
|
|
1241
|
-
callback:
|
|
1242
|
-
|
|
1243
|
-
data: "0x",
|
|
1244
|
-
gasLimit: 0n
|
|
1245
|
-
},
|
|
1246
|
-
consumed: 0n,
|
|
1305
|
+
callback: config?.callback ?? callbackBySide,
|
|
1306
|
+
consumed: consumed2,
|
|
1247
1307
|
blockNumber: Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
|
|
1248
1308
|
});
|
|
1249
1309
|
return offer;
|
|
1250
1310
|
}
|
|
1311
|
+
var weightedChoice = (pairs) => {
|
|
1312
|
+
const total = pairs.reduce((sum, [, weight]) => sum + weight, 0);
|
|
1313
|
+
let roll = Math.random() * total;
|
|
1314
|
+
for (const [value, weight] of pairs) {
|
|
1315
|
+
roll -= weight;
|
|
1316
|
+
if (roll < 0) return value;
|
|
1317
|
+
}
|
|
1318
|
+
return pairs[0][0];
|
|
1319
|
+
};
|
|
1251
1320
|
var domain = (chainId) => ({
|
|
1252
1321
|
chainId,
|
|
1253
1322
|
verifyingContract: zeroAddress
|
|
@@ -6173,6 +6242,7 @@ var RouterCmd = class _RouterCmd extends Command {
|
|
|
6173
6242
|
command.setOptionValue("rpcUrl", rpcUrl);
|
|
6174
6243
|
command.setOptionValue("routerServices", routerServices);
|
|
6175
6244
|
command.setOptionValue("logger", logger);
|
|
6245
|
+
command.setOptionValue("chain", chain);
|
|
6176
6246
|
return { routerServices };
|
|
6177
6247
|
}
|
|
6178
6248
|
// allows to use the logger defined in the setup function for the action of the command
|
|
@@ -6187,12 +6257,116 @@ var RouterCmd = class _RouterCmd extends Command {
|
|
|
6187
6257
|
}
|
|
6188
6258
|
};
|
|
6189
6259
|
|
|
6190
|
-
// src/cli/commands/
|
|
6260
|
+
// src/cli/commands/mock.ts
|
|
6261
|
+
var mockCmd = new RouterCmd("mock");
|
|
6262
|
+
mockCmd.description("Start Router mock.").addOption(
|
|
6263
|
+
new Option("--seed <n>", "Seed random offers to router").argParser((v) => Number(v)).default(0)
|
|
6264
|
+
).addOption(new Option("--file <path>", "Seed offers from a JSON file")).action(
|
|
6265
|
+
async (opts) => {
|
|
6266
|
+
const {
|
|
6267
|
+
port,
|
|
6268
|
+
routerServices: { liquidityStore, offerStore, routerApi },
|
|
6269
|
+
logger,
|
|
6270
|
+
chain
|
|
6271
|
+
} = opts;
|
|
6272
|
+
const stops = [];
|
|
6273
|
+
if (opts.seed > 0) {
|
|
6274
|
+
const offers2 = Array.from(Array(opts.seed ?? 0).keys()).map((_i) => ({
|
|
6275
|
+
offer: Offer_exports.random({
|
|
6276
|
+
chains: [chain],
|
|
6277
|
+
loanTokens: Array.from(chain.whitelistedAssets.values()),
|
|
6278
|
+
collateralTokens: Array.from(chain.whitelistedAssets.values()),
|
|
6279
|
+
assetsDecimals: {
|
|
6280
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": 6,
|
|
6281
|
+
// USDC
|
|
6282
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F": 18,
|
|
6283
|
+
// DAI
|
|
6284
|
+
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": 18,
|
|
6285
|
+
// WETH
|
|
6286
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599": 8,
|
|
6287
|
+
// WBTC
|
|
6288
|
+
"0x4200000000000000000000000000000000000006": 18,
|
|
6289
|
+
// WETH
|
|
6290
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913": 6,
|
|
6291
|
+
// USDC
|
|
6292
|
+
"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb": 18
|
|
6293
|
+
// DAI
|
|
6294
|
+
}
|
|
6295
|
+
}),
|
|
6296
|
+
status: "valid"
|
|
6297
|
+
}));
|
|
6298
|
+
await offerStore.createMany(offers2);
|
|
6299
|
+
for (const offer of offers2) {
|
|
6300
|
+
await liquidityStore.save({
|
|
6301
|
+
pools: [
|
|
6302
|
+
{
|
|
6303
|
+
id: offer.offer.hash,
|
|
6304
|
+
amount: offer.offer.assets
|
|
6305
|
+
}
|
|
6306
|
+
],
|
|
6307
|
+
offerPools: [
|
|
6308
|
+
{
|
|
6309
|
+
offerHash: offer.offer.hash,
|
|
6310
|
+
poolId: offer.offer.hash,
|
|
6311
|
+
amount: offer.offer.assets
|
|
6312
|
+
}
|
|
6313
|
+
],
|
|
6314
|
+
links: []
|
|
6315
|
+
});
|
|
6316
|
+
}
|
|
6317
|
+
logger.info({ msg: `Offers seeded`, count: opts.seed });
|
|
6318
|
+
}
|
|
6319
|
+
if (opts.file) {
|
|
6320
|
+
const offers2 = await getOffersFromFile(opts.file);
|
|
6321
|
+
await offerStore.createMany(offers2.map((ro) => ({ offer: ro })));
|
|
6322
|
+
for (const offer of offers2) {
|
|
6323
|
+
await liquidityStore.save({
|
|
6324
|
+
pools: [
|
|
6325
|
+
{
|
|
6326
|
+
id: offer.hash,
|
|
6327
|
+
amount: offer.assets
|
|
6328
|
+
}
|
|
6329
|
+
],
|
|
6330
|
+
offerPools: [
|
|
6331
|
+
{
|
|
6332
|
+
offerHash: offer.hash,
|
|
6333
|
+
poolId: offer.hash,
|
|
6334
|
+
amount: offer.assets
|
|
6335
|
+
}
|
|
6336
|
+
],
|
|
6337
|
+
links: []
|
|
6338
|
+
});
|
|
6339
|
+
}
|
|
6340
|
+
logger.info({ msg: `Offers seeded from file`, count: offers2.length, file: opts.file });
|
|
6341
|
+
}
|
|
6342
|
+
await routerApi.serve({ port });
|
|
6343
|
+
logger.info({ msg: `API started`, url: `http://localhost:${port}` });
|
|
6344
|
+
const shutdown = async (signal) => {
|
|
6345
|
+
logger.warn({ msg: `Shutdown signal`, signal });
|
|
6346
|
+
try {
|
|
6347
|
+
stops.forEach((stop) => stop());
|
|
6348
|
+
} catch {
|
|
6349
|
+
}
|
|
6350
|
+
process.exit(0);
|
|
6351
|
+
};
|
|
6352
|
+
process.once("SIGINT", () => void shutdown("SIGINT"));
|
|
6353
|
+
process.once("SIGTERM", () => void shutdown("SIGTERM"));
|
|
6354
|
+
process.stdin.resume();
|
|
6355
|
+
}
|
|
6356
|
+
);
|
|
6357
|
+
async function getOffersFromFile(file) {
|
|
6358
|
+
const raw = await readFile(file, "utf8");
|
|
6359
|
+
const json = JSON.parse(raw);
|
|
6360
|
+
const items = Array.isArray(json) ? json : json.offers ?? [];
|
|
6361
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
6362
|
+
console.log("No offers found in file");
|
|
6363
|
+
return [];
|
|
6364
|
+
}
|
|
6365
|
+
return items.map((o) => Offer_exports.from(o));
|
|
6366
|
+
}
|
|
6191
6367
|
var startCmd = new RouterCmd("start");
|
|
6192
6368
|
startCmd.description("Start Router services.").addOption(
|
|
6193
6369
|
new Option("--block-window <n>", "Block window to get logs from").argParser((v) => Number(v)).default(100)
|
|
6194
|
-
).addOption(
|
|
6195
|
-
new Option("--seed <n>", "Seed random offers to router").argParser((v) => Number(v)).default(0)
|
|
6196
6370
|
).addOption(new Option("--file <path>", "Seed offers from a JSON file")).addOption(
|
|
6197
6371
|
new Option("--max-block-number <n>", "Block number at which to stop indexing").argParser(
|
|
6198
6372
|
(v) => Number(v)
|
|
@@ -6205,24 +6379,10 @@ startCmd.description("Start Router services.").addOption(
|
|
|
6205
6379
|
async (opts) => {
|
|
6206
6380
|
const {
|
|
6207
6381
|
port,
|
|
6208
|
-
routerServices: {
|
|
6382
|
+
routerServices: { indexer, routerApi },
|
|
6209
6383
|
logger
|
|
6210
6384
|
} = opts;
|
|
6211
6385
|
const stops = [];
|
|
6212
|
-
if (opts.seed > 0) {
|
|
6213
|
-
await offerStore.createMany(
|
|
6214
|
-
Array.from(Array(opts.seed ?? 0).keys()).map((_i) => ({
|
|
6215
|
-
offer: Offer_exports.random(),
|
|
6216
|
-
status: "valid"
|
|
6217
|
-
}))
|
|
6218
|
-
);
|
|
6219
|
-
logger.info({ msg: `Offers seeded`, count: opts.seed });
|
|
6220
|
-
}
|
|
6221
|
-
if (opts.file) {
|
|
6222
|
-
const offers2 = await getOffersFromFile(opts.file);
|
|
6223
|
-
await offerStore.createMany(offers2.map((ro) => ({ offer: ro })));
|
|
6224
|
-
logger.info({ msg: `Offers seeded from file`, count: offers2.length, file: opts.file });
|
|
6225
|
-
}
|
|
6226
6386
|
const selectedServices = new Set(opts.services);
|
|
6227
6387
|
if (selectedServices.has("indexer")) {
|
|
6228
6388
|
stops.push(await indexer.start());
|
|
@@ -6245,16 +6405,6 @@ startCmd.description("Start Router services.").addOption(
|
|
|
6245
6405
|
process.stdin.resume();
|
|
6246
6406
|
}
|
|
6247
6407
|
);
|
|
6248
|
-
async function getOffersFromFile(file) {
|
|
6249
|
-
const raw = await readFile(file, "utf8");
|
|
6250
|
-
const json = JSON.parse(raw);
|
|
6251
|
-
const items = Array.isArray(json) ? json : json.offers ?? [];
|
|
6252
|
-
if (!Array.isArray(items) || items.length === 0) {
|
|
6253
|
-
console.log("No offers found in file");
|
|
6254
|
-
return [];
|
|
6255
|
-
}
|
|
6256
|
-
return items.map((o) => Offer_exports.from(o));
|
|
6257
|
-
}
|
|
6258
6408
|
var tunnelCmd = new Command("tunnel");
|
|
6259
6409
|
tunnelCmd.description("Expose the local Router via ngrok").addOption(
|
|
6260
6410
|
new Option("--port <n>").env("ROUTER_PORT").default(7891).argParser((v) => Number(v))
|
|
@@ -6286,6 +6436,7 @@ cli.name(package_default.name.split("/")[1] || "cli").description(package_defaul
|
|
|
6286
6436
|
cli.addCommand(startCmd);
|
|
6287
6437
|
cli.addCommand(tunnelCmd);
|
|
6288
6438
|
cli.addCommand(mempoolCmd);
|
|
6439
|
+
cli.addCommand(mockCmd);
|
|
6289
6440
|
cli.command("__commands", { hidden: true }).description("internal: list commands").action(() => {
|
|
6290
6441
|
const names2 = cli.commands.map((c) => c.name());
|
|
6291
6442
|
console.log(JSON.stringify(names2));
|