@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 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.17",
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 loanToken = privateKeyToAccount(generatePrivateKey()).address;
1220
- const maturity = from3("end_of_month");
1221
- const expiry = from3("end_of_week") - 1;
1222
- const lltv = from(0.965);
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: BigInt(Math.floor(Math.random() * 1e6)),
1226
- rate: BigInt(Math.floor(Math.random() * 1e6)),
1288
+ offering: config?.offering ?? privateKeyToAccount(generatePrivateKey()).address,
1289
+ assets: assetsScaled,
1290
+ rate,
1227
1291
  maturity,
1228
- expiry,
1229
- start: expiry - 10,
1292
+ expiry: config?.expiry ?? maturity - 1,
1293
+ start: config?.start ?? maturity - 10,
1230
1294
  nonce: BigInt(Math.floor(Math.random() * 1e6)),
1231
- buy: Math.random() > 0.5,
1232
- chainId: 1n,
1295
+ buy,
1296
+ chainId: chain.id,
1233
1297
  loanToken,
1234
- collaterals: [
1298
+ collaterals: config?.collaterals ?? [
1235
1299
  from2({
1236
- asset: zeroAddress,
1300
+ asset: collateralAsset,
1237
1301
  oracle: zeroAddress,
1238
1302
  lltv
1239
1303
  })
1240
1304
  ],
1241
- callback: {
1242
- address: zeroAddress,
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/start.ts
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: { offerStore, indexer, routerApi },
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));