@morpho-dev/router 0.1.16 → 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.
@@ -1,11 +1,11 @@
1
1
  import { z } from 'zod/v4';
2
- import { maxUint256, isAddress, isHex, decodeAbiParameters, encodeAbiParameters, keccak256, zeroAddress, hashTypedData, getAddress, publicActions } from 'viem';
2
+ import { maxUint256, isAddress, isHex, getAddress, decodeAbiParameters, encodeAbiParameters, keccak256, zeroAddress, hashTypedData, publicActions } from 'viem';
3
+ import { createDocument } from 'zod-openapi';
3
4
  import { getBlock, getLogs } from 'viem/actions';
4
5
  import { base, mainnet, anvil } from 'viem/chains';
5
6
  import * as z7 from 'zod';
6
- import { Base64 } from 'js-base64';
7
7
  import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
8
- import { createDocument } from 'zod-openapi';
8
+ import { Base64 } from 'js-base64';
9
9
 
10
10
  var __defProp = Object.defineProperty;
11
11
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -15,7 +15,7 @@ var __export = (target, all) => {
15
15
  };
16
16
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
17
17
 
18
- // src/api/Api/Schema/index.ts
18
+ // src/api/Schema/index.ts
19
19
  var Schema_exports = {};
20
20
  __export(Schema_exports, {
21
21
  ChainHealth: () => ChainHealth,
@@ -37,26 +37,88 @@ var CollectorHealth = z.object({
37
37
  lag: z.number().nullable(),
38
38
  status: z.enum(["live", "lagging", "unknown"])
39
39
  });
40
- var CollectorsHealthResponse = z.object({
41
- collectors: z.array(CollectorHealth)
42
- });
40
+ var CollectorsHealthResponse = z.array(CollectorHealth);
43
41
  var ChainHealth = z.object({
44
42
  chain_id: z.number(),
45
43
  block_number: z.number(),
46
44
  updated_at: z.string()
47
45
  });
48
- var ChainsHealthResponse = z.object({
49
- chains: z.array(ChainHealth)
50
- });
46
+ var ChainsHealthResponse = z.array(ChainHealth);
51
47
  var RouterStatusResponse = z.object({
52
48
  status: z.enum(["live", "syncing"])
53
49
  });
54
50
 
55
- // src/api/Api/Schema/ObligationResponse.ts
51
+ // src/api/Schema/ObligationResponse.ts
56
52
  var ObligationResponse_exports = {};
57
53
  __export(ObligationResponse_exports, {
58
- from: () => from6
54
+ from: () => from
55
+ });
56
+
57
+ // src/utils/Format.ts
58
+ var Format_exports = {};
59
+ __export(Format_exports, {
60
+ fromSnakeCase: () => fromSnakeCase,
61
+ toSnakeCase: () => toSnakeCase
62
+ });
63
+ function toSnakeCase(obj) {
64
+ return stringifyBigint(
65
+ processObject(
66
+ obj,
67
+ (s) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`),
68
+ (value) => typeof value === "string" && isAddress(value.toLowerCase()) ? getAddress(value.toLowerCase()) : value
69
+ )
70
+ );
71
+ }
72
+ function fromSnakeCase(obj) {
73
+ return processObject(
74
+ obj,
75
+ (s) => isAddress(s.toLowerCase()) ? s : s.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),
76
+ (value) => typeof value === "string" && isAddress(value.toLowerCase()) ? value.toLowerCase() : value
77
+ );
78
+ }
79
+ function processObject(obj, fnKey, fnValue) {
80
+ if (typeof obj !== "object" || obj === null) return obj;
81
+ if (Array.isArray(obj)) return obj.map((item) => processObject(item, fnKey, fnValue));
82
+ return Object.entries(obj).reduce(
83
+ (acc, [key, value]) => {
84
+ const newKey = fnKey(key);
85
+ acc[newKey] = typeof value === "object" && value !== null ? processObject(value, fnKey, fnValue) : fnValue(value);
86
+ return acc;
87
+ },
88
+ {}
89
+ );
90
+ }
91
+ function stringifyBigint(value) {
92
+ if (typeof value === "bigint") return value.toString();
93
+ if (Array.isArray(value)) return value.map(stringifyBigint);
94
+ if (value && typeof value === "object") {
95
+ const out = {};
96
+ for (const [k, v] of Object.entries(value)) {
97
+ out[k] = stringifyBigint(v);
98
+ }
99
+ return out;
100
+ }
101
+ return value;
102
+ }
103
+
104
+ // src/api/Schema/ObligationResponse.ts
105
+ function from(obligation, quote) {
106
+ return toSnakeCase({
107
+ id: quote.obligationId,
108
+ ...obligation,
109
+ ask: quote.ask,
110
+ bid: quote.bid
111
+ });
112
+ }
113
+
114
+ // src/api/Schema/OfferResponse.ts
115
+ var OfferResponse_exports = {};
116
+ __export(OfferResponse_exports, {
117
+ from: () => from2
59
118
  });
119
+ function from2(offer) {
120
+ return toSnakeCase(offer);
121
+ }
60
122
 
61
123
  // src/core/Abi.ts
62
124
  var Abi_exports = {};
@@ -425,8 +487,12 @@ var chains = {
425
487
  [
426
488
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
427
489
  // USDC
428
- "0x6B175474E89094C44Da98b954EedeAC495271d0F"
490
+ "0x6B175474E89094C44Da98b954EedeAC495271d0F",
429
491
  // DAI
492
+ "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
493
+ // WETH
494
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
495
+ // WBTC
430
496
  ].map((address) => address.toLowerCase())
431
497
  ),
432
498
  morpho: "0x0000000000000000000000000000000000000000",
@@ -449,8 +515,12 @@ var chains = {
449
515
  [
450
516
  "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
451
517
  // USDC
452
- "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb"
518
+ "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
453
519
  // DAI
520
+ "0x4200000000000000000000000000000000000006",
521
+ // WETH
522
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
523
+ // WBTC
454
524
  ].map((address) => address.toLowerCase())
455
525
  ),
456
526
  morpho: "0x0000000000000000000000000000000000000000",
@@ -473,8 +543,12 @@ var chains = {
473
543
  [
474
544
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
475
545
  // USDC
476
- "0x6B175474E89094C44Da98b954EedeAC495271d0F"
546
+ "0x6B175474E89094C44Da98b954EedeAC495271d0F",
477
547
  // DAI
548
+ "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
549
+ // WETH
550
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
551
+ // WBTC
478
552
  ].map((address) => address.toLowerCase())
479
553
  ),
480
554
  morpho: "0x11a002d45db720ed47a80d2f3489cba5b833eaf5",
@@ -498,8 +572,12 @@ var chains = {
498
572
  [
499
573
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
500
574
  // USDC
501
- "0x6B175474E89094C44Da98b954EedeAC495271d0F"
575
+ "0x6B175474E89094C44Da98b954EedeAC495271d0F",
502
576
  // DAI
577
+ "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
578
+ // WETH
579
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
580
+ // WBTC
503
581
  ].map((address) => address.toLowerCase())
504
582
  ),
505
583
  morpho: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
@@ -627,7 +705,7 @@ var Collateral_exports = {};
627
705
  __export(Collateral_exports, {
628
706
  CollateralSchema: () => CollateralSchema,
629
707
  CollateralsSchema: () => CollateralsSchema,
630
- from: () => from2
708
+ from: () => from4
631
709
  });
632
710
  var transformHex = (val, ctx) => {
633
711
  if (isHex(val)) return val;
@@ -657,11 +735,11 @@ __export(LLTV_exports, {
657
735
  InvalidOptionError: () => InvalidOptionError,
658
736
  LLTVSchema: () => LLTVSchema,
659
737
  Options: () => Options,
660
- from: () => from
738
+ from: () => from3
661
739
  });
662
740
  var Options = [0.385, 0.5, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965, 0.98];
663
741
  var LLTV_SCALED = Options.map((lltv) => BigInt(lltv * 10 ** 18));
664
- function from(lltv) {
742
+ function from3(lltv) {
665
743
  if (typeof lltv === "bigint" && !LLTV_SCALED.includes(lltv)) throw new InvalidLLTVError(lltv);
666
744
  if (typeof lltv === "bigint") return lltv;
667
745
  if (typeof lltv === "number" && !Options.includes(lltv)) throw new InvalidOptionError(lltv);
@@ -690,7 +768,7 @@ var InvalidLLTVError = class extends BaseError {
690
768
  var LLTVSchema = z7.bigint({ coerce: true }).refine(
691
769
  (lltv) => {
692
770
  try {
693
- from(lltv);
771
+ from3(lltv);
694
772
  return true;
695
773
  } catch (_) {
696
774
  return false;
@@ -701,7 +779,7 @@ var LLTVSchema = z7.bigint({ coerce: true }).refine(
701
779
  return "Invalid LLTV: must be one of 0.385, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965 or 0.98 (scaled by 1e18)";
702
780
  }
703
781
  }
704
- ).transform((lltv) => from(lltv));
782
+ ).transform((lltv) => from3(lltv));
705
783
 
706
784
  // src/core/Collateral.ts
707
785
  var CollateralSchema = z7.object({
@@ -737,105 +815,14 @@ var CollateralsSchema = z7.array(CollateralSchema).min(1, { message: "At least o
737
815
  message: "Collaterals must not contain duplicate assets"
738
816
  }
739
817
  );
740
- var from2 = (parameters) => {
818
+ var from4 = (parameters) => {
741
819
  return {
742
820
  asset: parameters.asset.toLowerCase(),
743
- lltv: from(parameters.lltv),
821
+ lltv: from3(parameters.lltv),
744
822
  oracle: parameters.oracle.toLowerCase()
745
823
  };
746
824
  };
747
825
 
748
- // src/core/Cursor.ts
749
- var Cursor_exports = {};
750
- __export(Cursor_exports, {
751
- decode: () => decode,
752
- encode: () => encode,
753
- validate: () => validate
754
- });
755
- function validate(cursor) {
756
- if (!cursor || typeof cursor !== "object") {
757
- throw new Error("Cursor must be an object");
758
- }
759
- const c = cursor;
760
- if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
761
- throw new Error(
762
- `Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
763
- );
764
- }
765
- if (!["asc", "desc"].includes(c.dir)) {
766
- throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
767
- }
768
- if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
769
- throw new Error(
770
- `Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
771
- );
772
- }
773
- const validations = {
774
- rate: {
775
- field: "rate",
776
- type: "string",
777
- pattern: /^\d+$/,
778
- error: "numeric string"
779
- },
780
- amount: {
781
- field: "assets",
782
- type: "string",
783
- pattern: /^\d+$/,
784
- error: "numeric string"
785
- },
786
- maturity: {
787
- field: "maturity",
788
- type: "number",
789
- validator: (val) => val > 0,
790
- error: "positive number"
791
- },
792
- expiry: {
793
- field: "expiry",
794
- type: "number",
795
- validator: (val) => val > 0,
796
- error: "positive number"
797
- }
798
- };
799
- const validation = validations[c.sort];
800
- if (!validation) {
801
- throw new Error(`Invalid sort field: ${c.sort}`);
802
- }
803
- const fieldValue = c[validation.field];
804
- if (!fieldValue) {
805
- throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
806
- }
807
- if (typeof fieldValue !== validation.type) {
808
- throw new Error(
809
- `${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
810
- );
811
- }
812
- if (validation.pattern && !validation.pattern.test(fieldValue)) {
813
- throw new Error(
814
- `Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
815
- );
816
- }
817
- if (validation.validator && !validation.validator(fieldValue)) {
818
- throw new Error(
819
- `Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
820
- );
821
- }
822
- if (c.page !== void 0) {
823
- if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
824
- throw new Error("Invalid page: must be a positive integer");
825
- }
826
- }
827
- return true;
828
- }
829
- function encode(c) {
830
- return Base64.encodeURL(JSON.stringify(c));
831
- }
832
- function decode(token) {
833
- if (!token) return null;
834
- const decoded = JSON.parse(Base64.decode(token));
835
- validate(decoded);
836
- return decoded;
837
- }
838
-
839
826
  // src/core/Liquidity.ts
840
827
  var Liquidity_exports = {};
841
828
  __export(Liquidity_exports, {
@@ -901,12 +888,12 @@ __export(Maturity_exports, {
901
888
  InvalidFormatError: () => InvalidFormatError,
902
889
  InvalidOptionError: () => InvalidOptionError2,
903
890
  MaturitySchema: () => MaturitySchema,
904
- from: () => from3
891
+ from: () => from5
905
892
  });
906
893
  var MaturitySchema = z7.number().int().refine(
907
894
  (maturity) => {
908
895
  try {
909
- from3(maturity);
896
+ from5(maturity);
910
897
  return true;
911
898
  } catch (_e) {
912
899
  return false;
@@ -931,7 +918,7 @@ var MaturityOptions = {
931
918
  end_of_quarter: () => endOfQuarter(),
932
919
  end_of_next_quarter: () => endOfNextQuarter()
933
920
  };
934
- function from3(ts) {
921
+ function from5(ts) {
935
922
  if (typeof ts === "string") {
936
923
  if (ts in MaturityOptions) return MaturityOptions[ts]();
937
924
  throw new InvalidOptionError2(ts);
@@ -1009,71 +996,22 @@ __export(Obligation_exports, {
1009
996
  CollateralsAreNotSortedError: () => CollateralsAreNotSortedError,
1010
997
  InvalidObligationError: () => InvalidObligationError,
1011
998
  ObligationSchema: () => ObligationSchema,
1012
- from: () => from4,
999
+ from: () => from6,
1013
1000
  fromSnakeCase: () => fromSnakeCase2,
1014
1001
  id: () => id,
1015
1002
  random: () => random
1016
1003
  });
1017
-
1018
- // src/utils/Format.ts
1019
- var Format_exports = {};
1020
- __export(Format_exports, {
1021
- fromSnakeCase: () => fromSnakeCase,
1022
- toSnakeCase: () => toSnakeCase
1023
- });
1024
- function toSnakeCase(obj) {
1025
- return stringifyBigint(
1026
- processObject(
1027
- obj,
1028
- (s) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`),
1029
- (value) => typeof value === "string" && isAddress(value.toLowerCase()) ? getAddress(value.toLowerCase()) : value
1030
- )
1031
- );
1032
- }
1033
- function fromSnakeCase(obj) {
1034
- return processObject(
1035
- obj,
1036
- (s) => isAddress(s.toLowerCase()) ? s : s.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),
1037
- (value) => typeof value === "string" && isAddress(value.toLowerCase()) ? value.toLowerCase() : value
1038
- );
1039
- }
1040
- function processObject(obj, fnKey, fnValue) {
1041
- if (typeof obj !== "object" || obj === null) return obj;
1042
- if (Array.isArray(obj)) return obj.map((item) => processObject(item, fnKey, fnValue));
1043
- return Object.entries(obj).reduce(
1044
- (acc, [key, value]) => {
1045
- const newKey = fnKey(key);
1046
- acc[newKey] = typeof value === "object" && value !== null ? processObject(value, fnKey, fnValue) : fnValue(value);
1047
- return acc;
1048
- },
1049
- {}
1050
- );
1051
- }
1052
- function stringifyBigint(value) {
1053
- if (typeof value === "bigint") return value.toString();
1054
- if (Array.isArray(value)) return value.map(stringifyBigint);
1055
- if (value && typeof value === "object") {
1056
- const out = {};
1057
- for (const [k, v] of Object.entries(value)) {
1058
- out[k] = stringifyBigint(v);
1059
- }
1060
- return out;
1061
- }
1062
- return value;
1063
- }
1064
-
1065
- // src/core/Obligation.ts
1066
1004
  var ObligationSchema = z7.object({
1067
1005
  chainId: z7.bigint({ coerce: true }).min(0n).max(maxUint256),
1068
1006
  loanToken: z7.string().transform(transformAddress),
1069
1007
  collaterals: CollateralsSchema,
1070
1008
  maturity: MaturitySchema
1071
1009
  });
1072
- function from4(parameters) {
1010
+ function from6(parameters) {
1073
1011
  try {
1074
1012
  const parsedObligation = ObligationSchema.parse({
1075
1013
  ...parameters,
1076
- maturity: from3(parameters.maturity)
1014
+ maturity: from5(parameters.maturity)
1077
1015
  });
1078
1016
  return {
1079
1017
  chainId: parsedObligation.chainId,
@@ -1086,7 +1024,7 @@ function from4(parameters) {
1086
1024
  }
1087
1025
  }
1088
1026
  function fromSnakeCase2(input) {
1089
- return from4(fromSnakeCase(input));
1027
+ return from6(fromSnakeCase(input));
1090
1028
  }
1091
1029
  function id(obligation) {
1092
1030
  let lastAsset = "";
@@ -1124,17 +1062,17 @@ function id(obligation) {
1124
1062
  );
1125
1063
  }
1126
1064
  function random() {
1127
- return from4({
1065
+ return from6({
1128
1066
  chainId: 1n,
1129
1067
  loanToken: privateKeyToAccount(generatePrivateKey()).address,
1130
1068
  collaterals: [
1131
- from2({
1069
+ from4({
1132
1070
  asset: privateKeyToAccount(generatePrivateKey()).address,
1133
1071
  oracle: privateKeyToAccount(generatePrivateKey()).address,
1134
1072
  lltv: 0.965
1135
1073
  })
1136
1074
  ],
1137
- maturity: from3("end_of_next_quarter")
1075
+ maturity: from5("end_of_next_quarter")
1138
1076
  });
1139
1077
  }
1140
1078
  var InvalidObligationError = class extends BaseError {
@@ -1158,10 +1096,10 @@ __export(Offer_exports, {
1158
1096
  OfferHashSchema: () => OfferHashSchema,
1159
1097
  OfferSchema: () => OfferSchema,
1160
1098
  consumedEvent: () => consumedEvent,
1161
- decode: () => decode2,
1099
+ decode: () => decode,
1162
1100
  domain: () => domain,
1163
- encode: () => encode2,
1164
- from: () => from5,
1101
+ encode: () => encode,
1102
+ from: () => from7,
1165
1103
  fromConsumedLog: () => fromConsumedLog,
1166
1104
  fromSnakeCase: () => fromSnakeCase3,
1167
1105
  hash: () => hash,
@@ -1330,7 +1268,7 @@ var OfferSchema = (parameters) => {
1330
1268
  path: ["expiry"]
1331
1269
  });
1332
1270
  };
1333
- function from5(input) {
1271
+ function from7(input) {
1334
1272
  try {
1335
1273
  const parsedOffer = OfferSchema({ omitHash: true }).parse(input);
1336
1274
  const parsedHash = OfferHashSchema.parse(hash(parsedOffer));
@@ -1343,44 +1281,97 @@ function from5(input) {
1343
1281
  }
1344
1282
  }
1345
1283
  function fromSnakeCase3(input) {
1346
- return from5(fromSnakeCase(input));
1284
+ return from7(fromSnakeCase(input));
1347
1285
  }
1348
1286
  function toSnakeCase2(offer) {
1349
1287
  return toSnakeCase(offer);
1350
1288
  }
1351
- function random2() {
1352
- const loanToken = privateKeyToAccount(generatePrivateKey()).address;
1353
- const maturity = from3("end_of_month");
1354
- const expiry = from3("end_of_week") - 1;
1355
- const lltv = from(0.965);
1356
- const offer = from5({
1357
- offering: privateKeyToAccount(generatePrivateKey()).address,
1358
- assets: BigInt(Math.floor(Math.random() * 1e6)),
1359
- rate: BigInt(Math.floor(Math.random() * 1e6)),
1289
+ function random2(config) {
1290
+ const chain = config?.chains ? config.chains[Math.floor(Math.random() * config.chains.length)] : chains.ethereum;
1291
+ const loanToken = config?.loanTokens ? config.loanTokens[Math.floor(Math.random() * config.loanTokens.length)] : privateKeyToAccount(generatePrivateKey()).address;
1292
+ const collateralCandidates = config?.collateralTokens ? config.collateralTokens.filter((a) => a !== loanToken) : [privateKeyToAccount(generatePrivateKey()).address];
1293
+ const collateralAsset = collateralCandidates[Math.floor(Math.random() * collateralCandidates.length)];
1294
+ const maturityOption = weightedChoice([
1295
+ ["end_of_month", 1],
1296
+ ["end_of_next_month", 1]
1297
+ ]);
1298
+ const maturity = config?.maturity ?? from5(maturityOption);
1299
+ const lltv = from3(
1300
+ weightedChoice([
1301
+ [0.385, 1],
1302
+ [0.5, 1],
1303
+ [0.625, 2],
1304
+ [0.77, 8],
1305
+ [0.86, 10],
1306
+ [0.915, 8],
1307
+ [0.945, 6],
1308
+ [0.965, 4],
1309
+ [0.98, 2]
1310
+ ])
1311
+ );
1312
+ const buy = config?.buy !== void 0 ? config.buy : Math.random() > 0.5;
1313
+ const ONE = 1000000000000000000n;
1314
+ const qMin = buy ? 16 : 4;
1315
+ const qMax = buy ? 32 : 16;
1316
+ const len = qMax - qMin + 1;
1317
+ const ratePairs = Array.from(
1318
+ { length: len },
1319
+ (_, idx) => {
1320
+ const q = qMin + idx;
1321
+ const scaledRate = BigInt(q) * (ONE / 4n);
1322
+ const weight = buy ? 1 + idx : 1 + (len - 1 - idx);
1323
+ return [scaledRate, weight];
1324
+ }
1325
+ );
1326
+ const rate = config?.rate ?? weightedChoice(ratePairs);
1327
+ const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
1328
+ const unit = BigInt(10) ** BigInt(loanTokenDecimals);
1329
+ const amountBase = BigInt(100 + Math.floor(Math.random() * (1e6 - 100 + 1)));
1330
+ const assetsScaled = config?.assets ?? amountBase * unit;
1331
+ const consumed = config?.consumed !== void 0 ? config.consumed : Math.random() < 0.8 ? 0n : assetsScaled * BigInt(1 + Math.floor(Math.random() * 900)) / 1000n;
1332
+ const callbackBySide = (() => {
1333
+ if (buy) return { address: zeroAddress, data: "0x", gasLimit: 0n };
1334
+ const sellCallbackAddress = WhitelistedCallbackAddresses["sell_erc20_callback" /* SellERC20Callback */][0].toLowerCase();
1335
+ const amount = assetsScaled * 1000000000000000000000n;
1336
+ const data = encodeSellERC20Callback({
1337
+ collaterals: [collateralAsset],
1338
+ amounts: [amount]
1339
+ });
1340
+ return { address: sellCallbackAddress, data, gasLimit: 500000n };
1341
+ })();
1342
+ const offer = from7({
1343
+ offering: config?.offering ?? privateKeyToAccount(generatePrivateKey()).address,
1344
+ assets: assetsScaled,
1345
+ rate,
1360
1346
  maturity,
1361
- expiry,
1362
- start: expiry - 10,
1347
+ expiry: config?.expiry ?? maturity - 1,
1348
+ start: config?.start ?? maturity - 10,
1363
1349
  nonce: BigInt(Math.floor(Math.random() * 1e6)),
1364
- buy: Math.random() > 0.5,
1365
- chainId: 1n,
1350
+ buy,
1351
+ chainId: chain.id,
1366
1352
  loanToken,
1367
- collaterals: [
1368
- from2({
1369
- asset: zeroAddress,
1353
+ collaterals: config?.collaterals ?? [
1354
+ from4({
1355
+ asset: collateralAsset,
1370
1356
  oracle: zeroAddress,
1371
1357
  lltv
1372
1358
  })
1373
1359
  ],
1374
- callback: {
1375
- address: zeroAddress,
1376
- data: "0x",
1377
- gasLimit: 0n
1378
- },
1379
- consumed: 0n,
1360
+ callback: config?.callback ?? callbackBySide,
1361
+ consumed,
1380
1362
  blockNumber: Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
1381
1363
  });
1382
1364
  return offer;
1383
1365
  }
1366
+ var weightedChoice = (pairs) => {
1367
+ const total = pairs.reduce((sum, [, weight]) => sum + weight, 0);
1368
+ let roll = Math.random() * total;
1369
+ for (const [value, weight] of pairs) {
1370
+ roll -= weight;
1371
+ if (roll < 0) return value;
1372
+ }
1373
+ return pairs[0][0];
1374
+ };
1384
1375
  var domain = (chainId) => ({
1385
1376
  chainId,
1386
1377
  verifyingContract: zeroAddress
@@ -1463,7 +1454,7 @@ function hash(offer) {
1463
1454
  }
1464
1455
  function obligationId(offer) {
1465
1456
  return id(
1466
- from4({
1457
+ from6({
1467
1458
  chainId: offer.chainId,
1468
1459
  loanToken: offer.loanToken,
1469
1460
  collaterals: offer.collaterals,
@@ -1502,7 +1493,7 @@ var OfferAbi = [
1502
1493
  },
1503
1494
  { name: "signature", type: "bytes" }
1504
1495
  ];
1505
- function encode2(offer) {
1496
+ function encode(offer) {
1506
1497
  return encodeAbiParameters(OfferAbi, [
1507
1498
  offer.offering,
1508
1499
  offer.assets,
@@ -1519,18 +1510,18 @@ function encode2(offer) {
1519
1510
  offer.signature ?? "0x"
1520
1511
  ]);
1521
1512
  }
1522
- function decode2(data, blockNumber) {
1513
+ function decode(data, blockNumber) {
1523
1514
  let decoded;
1524
1515
  try {
1525
1516
  decoded = decodeAbiParameters(OfferAbi, data);
1526
1517
  } catch (error) {
1527
1518
  throw new InvalidOfferError(error);
1528
1519
  }
1529
- const offer = from5({
1520
+ const offer = from7({
1530
1521
  offering: decoded[0],
1531
1522
  assets: decoded[1],
1532
1523
  rate: decoded[2],
1533
- maturity: from3(Number(decoded[3])),
1524
+ maturity: from5(Number(decoded[3])),
1534
1525
  expiry: Number(decoded[4]),
1535
1526
  nonce: decoded[5],
1536
1527
  buy: decoded[6],
@@ -1538,7 +1529,7 @@ function decode2(data, blockNumber) {
1538
1529
  loanToken: decoded[8],
1539
1530
  start: Number(decoded[9]),
1540
1531
  collaterals: decoded[10].map((c) => {
1541
- return from2({
1532
+ return from4({
1542
1533
  asset: c.asset,
1543
1534
  oracle: c.oracle,
1544
1535
  lltv: c.lltv
@@ -1589,22 +1580,152 @@ var AccountNotSetError = class extends BaseError {
1589
1580
  }
1590
1581
  };
1591
1582
 
1583
+ // src/core/Quote.ts
1584
+ var Quote_exports = {};
1585
+ __export(Quote_exports, {
1586
+ InvalidQuoteError: () => InvalidQuoteError,
1587
+ QuoteSchema: () => QuoteSchema,
1588
+ from: () => from8,
1589
+ fromSnakeCase: () => fromSnakeCase4,
1590
+ random: () => random3
1591
+ });
1592
+ var QuoteSchema = z7.object({
1593
+ obligationId: z7.string().transform(transformHex),
1594
+ ask: z7.object({
1595
+ rate: z7.bigint({ coerce: true }).min(0n).max(maxUint256)
1596
+ }),
1597
+ bid: z7.object({
1598
+ rate: z7.bigint({ coerce: true }).min(0n).max(maxUint256)
1599
+ })
1600
+ });
1601
+ function from8(parameters) {
1602
+ try {
1603
+ const parsedQuote = QuoteSchema.parse(parameters);
1604
+ return {
1605
+ obligationId: parsedQuote.obligationId,
1606
+ ask: parsedQuote.ask,
1607
+ bid: parsedQuote.bid
1608
+ };
1609
+ } catch (error) {
1610
+ throw new InvalidQuoteError(error);
1611
+ }
1612
+ }
1613
+ function fromSnakeCase4(snake) {
1614
+ return from8(fromSnakeCase(snake));
1615
+ }
1616
+ function random3() {
1617
+ return from8({
1618
+ obligationId: Obligation_exports.id(Obligation_exports.random()),
1619
+ ask: {
1620
+ rate: BigInt(Math.floor(Math.random() * 1e6))
1621
+ },
1622
+ bid: {
1623
+ rate: BigInt(Math.floor(Math.random() * 1e6))
1624
+ }
1625
+ });
1626
+ }
1627
+ var InvalidQuoteError = class extends BaseError {
1628
+ constructor(error) {
1629
+ super("Invalid quote.", { cause: error });
1630
+ __publicField(this, "name", "Quote.InvalidQuoteError");
1631
+ }
1632
+ };
1633
+
1592
1634
  // src/core/types.ts
1593
1635
  var BrandTypeId = Symbol.for("mempool/Brand");
1594
1636
 
1595
- // src/api/Api/Schema/ObligationResponse.ts
1596
- function from6(obligation) {
1597
- return toSnakeCase({ id: Obligation_exports.id(obligation), ...obligation });
1598
- }
1599
-
1600
- // src/api/Api/Schema/OfferResponse.ts
1601
- var OfferResponse_exports = {};
1602
- __export(OfferResponse_exports, {
1603
- from: () => from7
1637
+ // src/stores/utils/Cursor.ts
1638
+ var Cursor_exports = {};
1639
+ __export(Cursor_exports, {
1640
+ decode: () => decode2,
1641
+ encode: () => encode2,
1642
+ validate: () => validate
1604
1643
  });
1605
- function from7(offer) {
1606
- return toSnakeCase(offer);
1644
+ function validate(cursor) {
1645
+ if (!cursor || typeof cursor !== "object") {
1646
+ throw new Error("Cursor must be an object");
1647
+ }
1648
+ const c = cursor;
1649
+ if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
1650
+ throw new Error(
1651
+ `Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
1652
+ );
1653
+ }
1654
+ if (!["asc", "desc"].includes(c.dir)) {
1655
+ throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
1656
+ }
1657
+ if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
1658
+ throw new Error(
1659
+ `Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
1660
+ );
1661
+ }
1662
+ const validations = {
1663
+ rate: {
1664
+ field: "rate",
1665
+ type: "string",
1666
+ pattern: /^\d+$/,
1667
+ error: "numeric string"
1668
+ },
1669
+ amount: {
1670
+ field: "assets",
1671
+ type: "string",
1672
+ pattern: /^\d+$/,
1673
+ error: "numeric string"
1674
+ },
1675
+ maturity: {
1676
+ field: "maturity",
1677
+ type: "number",
1678
+ validator: (val) => val > 0,
1679
+ error: "positive number"
1680
+ },
1681
+ expiry: {
1682
+ field: "expiry",
1683
+ type: "number",
1684
+ validator: (val) => val > 0,
1685
+ error: "positive number"
1686
+ }
1687
+ };
1688
+ const validation = validations[c.sort];
1689
+ if (!validation) {
1690
+ throw new Error(`Invalid sort field: ${c.sort}`);
1691
+ }
1692
+ const fieldValue = c[validation.field];
1693
+ if (!fieldValue) {
1694
+ throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
1695
+ }
1696
+ if (typeof fieldValue !== validation.type) {
1697
+ throw new Error(
1698
+ `${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
1699
+ );
1700
+ }
1701
+ if (validation.pattern && !validation.pattern.test(fieldValue)) {
1702
+ throw new Error(
1703
+ `Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
1704
+ );
1705
+ }
1706
+ if (validation.validator && !validation.validator(fieldValue)) {
1707
+ throw new Error(
1708
+ `Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
1709
+ );
1710
+ }
1711
+ if (c.page !== void 0) {
1712
+ if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
1713
+ throw new Error("Invalid page: must be a positive integer");
1714
+ }
1715
+ }
1716
+ return true;
1717
+ }
1718
+ function encode2(c) {
1719
+ return Base64.encodeURL(JSON.stringify(c));
1720
+ }
1721
+ function decode2(token) {
1722
+ if (!token) return null;
1723
+ const decoded = JSON.parse(Base64.decode(token));
1724
+ validate(decoded);
1725
+ return decoded;
1607
1726
  }
1727
+
1728
+ // src/api/Schema/requests.ts
1608
1729
  var MAX_LIMIT = 100;
1609
1730
  var DEFAULT_LIMIT = 20;
1610
1731
  var PaginationQueryParams = z7.object({
@@ -1667,14 +1788,74 @@ function safeParse(action, query, error) {
1667
1788
  });
1668
1789
  }
1669
1790
 
1670
- // src/api/Api/Schema/openapi.ts
1671
- var successResponseSchema = z.object({
1672
- status: z.literal("success"),
1673
- cursor: z.string().nullable(),
1674
- data: z.array(z.any()),
1675
- meta: z.object({
1676
- timestamp: z.string()
1677
- })
1791
+ // src/api/Schema/openapi.ts
1792
+ var timestampExample = "2024-01-01T12:00:00.000Z";
1793
+ var cursorExample = "eyJvZmZzZXQiOjEwMH0";
1794
+ function makeSuccessResponse(parameters) {
1795
+ const { dataSchema, dataDescription, dataExample, cursor } = parameters;
1796
+ const withDataMeta = dataDescription ? dataSchema.meta({ description: dataDescription }) : dataSchema;
1797
+ return z.object({
1798
+ status: z.literal("success"),
1799
+ cursor: z.string().nullable(),
1800
+ data: z.any(),
1801
+ meta: z.object({
1802
+ timestamp: z.string()
1803
+ })
1804
+ }).extend({
1805
+ data: withDataMeta
1806
+ }).meta({
1807
+ example: {
1808
+ status: "success",
1809
+ cursor,
1810
+ data: dataExample,
1811
+ meta: { timestamp: timestampExample }
1812
+ }
1813
+ });
1814
+ }
1815
+ var OffersSuccessResponseSchema = makeSuccessResponse({
1816
+ dataSchema: z.array(z.any()),
1817
+ dataDescription: "Offers matching the provided filters.",
1818
+ dataExample: [toSnakeCase(Offer_exports.random())],
1819
+ cursor: cursorExample
1820
+ });
1821
+ var ObligationsSuccessResponseSchema = makeSuccessResponse({
1822
+ dataSchema: z.array(z.any()),
1823
+ dataDescription: "Obligations known to the router.",
1824
+ dataExample: [toSnakeCase(Obligation_exports.random())],
1825
+ cursor: cursorExample
1826
+ });
1827
+ var RouterStatusSuccessResponseSchema = makeSuccessResponse({
1828
+ dataSchema: RouterStatusResponse,
1829
+ dataDescription: "Aggregated router status.",
1830
+ dataExample: { status: "live" },
1831
+ cursor: null
1832
+ });
1833
+ var CollectorsHealthSuccessResponseSchema = makeSuccessResponse({
1834
+ dataSchema: CollectorsHealthResponse,
1835
+ dataDescription: "Collectors health details and sync status.",
1836
+ dataExample: [
1837
+ {
1838
+ name: "mempool_offers",
1839
+ chain_id: "1",
1840
+ block_number: 21345678,
1841
+ updated_at: "2024-01-01T12:00:00.000Z",
1842
+ lag: 0,
1843
+ status: "live"
1844
+ }
1845
+ ],
1846
+ cursor: null
1847
+ });
1848
+ var ChainsHealthSuccessResponseSchema = makeSuccessResponse({
1849
+ dataSchema: ChainsHealthResponse,
1850
+ dataDescription: "Latest processed block per chain.",
1851
+ dataExample: [
1852
+ {
1853
+ chain_id: "1",
1854
+ block_number: 21345678,
1855
+ updated_at: "2024-01-01T12:00:00.000Z"
1856
+ }
1857
+ ],
1858
+ cursor: null
1678
1859
  });
1679
1860
  var errorResponseSchema = z.object({
1680
1861
  status: z.literal("error"),
@@ -1686,6 +1867,24 @@ var errorResponseSchema = z.object({
1686
1867
  meta: z.object({
1687
1868
  timestamp: z.string()
1688
1869
  })
1870
+ }).meta({
1871
+ description: "Error response wrapper.",
1872
+ example: {
1873
+ status: "error",
1874
+ error: {
1875
+ code: "VALIDATION_ERROR",
1876
+ message: "Invalid cursor format. Must be a valid base64url-encoded cursor object",
1877
+ details: [
1878
+ {
1879
+ field: "cursor",
1880
+ issue: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
1881
+ }
1882
+ ]
1883
+ },
1884
+ meta: {
1885
+ timestamp: timestampExample
1886
+ }
1887
+ }
1689
1888
  });
1690
1889
  var paths = {
1691
1890
  "/v1/offers": {
@@ -1701,7 +1900,7 @@ var paths = {
1701
1900
  description: "Success",
1702
1901
  content: {
1703
1902
  "application/json": {
1704
- schema: successResponseSchema
1903
+ schema: OffersSuccessResponseSchema
1705
1904
  }
1706
1905
  }
1707
1906
  },
@@ -1729,7 +1928,7 @@ var paths = {
1729
1928
  description: "Success",
1730
1929
  content: {
1731
1930
  "application/json": {
1732
- schema: successResponseSchema
1931
+ schema: ObligationsSuccessResponseSchema
1733
1932
  }
1734
1933
  }
1735
1934
  },
@@ -1754,7 +1953,7 @@ var paths = {
1754
1953
  description: "Success",
1755
1954
  content: {
1756
1955
  "application/json": {
1757
- schema: RouterStatusResponse
1956
+ schema: RouterStatusSuccessResponseSchema
1758
1957
  }
1759
1958
  }
1760
1959
  }
@@ -1771,7 +1970,7 @@ var paths = {
1771
1970
  description: "Success",
1772
1971
  content: {
1773
1972
  "application/json": {
1774
- schema: CollectorsHealthResponse
1973
+ schema: CollectorsHealthSuccessResponseSchema
1775
1974
  }
1776
1975
  }
1777
1976
  }
@@ -1788,7 +1987,7 @@ var paths = {
1788
1987
  description: "Success",
1789
1988
  content: {
1790
1989
  "application/json": {
1791
- schema: ChainsHealthResponse
1990
+ schema: ChainsHealthSuccessResponseSchema
1792
1991
  }
1793
1992
  }
1794
1993
  }
@@ -1820,14 +2019,14 @@ var OpenApi = createDocument({
1820
2019
  description: "Production server"
1821
2020
  },
1822
2021
  {
1823
- url: "http://localhost:8081",
2022
+ url: "http://localhost:7891",
1824
2023
  description: "Local development server"
1825
2024
  }
1826
2025
  ],
1827
2026
  paths
1828
2027
  });
1829
2028
 
1830
- // src/api/Client.ts
2029
+ // src/client/Client.ts
1831
2030
  var Client_exports = {};
1832
2031
  __export(Client_exports, {
1833
2032
  HttpForbiddenError: () => HttpForbiddenError,
@@ -1882,8 +2081,16 @@ async function getObligations(config, parameters) {
1882
2081
  if (parameters?.limit !== void 0) {
1883
2082
  url.searchParams.set("limit", parameters.limit.toString());
1884
2083
  }
1885
- const { cursor: returnedCursor, data: obligationsSnake } = await getApi(config, url);
1886
- const obligations = obligationsSnake.map(Obligation_exports.fromSnakeCase);
2084
+ const { cursor: returnedCursor, data: items } = await getApi(config, url);
2085
+ const obligations = items.map((item) => {
2086
+ const obligation = Obligation_exports.fromSnakeCase(item);
2087
+ const { obligationId: _, ...returned } = {
2088
+ id: () => Obligation_exports.id(obligation),
2089
+ ...obligation,
2090
+ ...Quote_exports.fromSnakeCase({ obligation_id: item.id, ask: item.ask, bid: item.bid })
2091
+ };
2092
+ return returned;
2093
+ });
1887
2094
  return {
1888
2095
  cursor: returnedCursor,
1889
2096
  obligations
@@ -2281,7 +2488,7 @@ __export(MempoolClient_exports, {
2281
2488
  });
2282
2489
  var DEFAULT_BATCH_SIZE2 = 100;
2283
2490
  var DEFAULT_BLOCK_WINDOW2 = 100;
2284
- function from8(parameters) {
2491
+ function from9(parameters) {
2285
2492
  const config = {
2286
2493
  client: parameters.client,
2287
2494
  mempoolAddress: parameters.mempoolAddress,
@@ -2426,9 +2633,9 @@ var ChainIdMismatchError = class extends BaseError {
2426
2633
 
2427
2634
  // src/mempool/MempoolClient.ts
2428
2635
  function connect2(parameters) {
2429
- return from8(parameters);
2636
+ return from9(parameters);
2430
2637
  }
2431
2638
 
2432
- export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, Collateral_exports as Collateral, Cursor_exports as Cursor, Errors_exports as Errors, Format_exports as Format, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Maturity_exports as Maturity, MempoolClient_exports as Mempool, Obligation_exports as Obligation, Offer_exports as Offer, Schema_exports as RouterApi, Client_exports as RouterClient, time_exports as Time, utils_exports as Utils, Validation_exports as Validation, ValidationRule_exports as ValidationRule };
2639
+ export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, Collateral_exports as Collateral, Cursor_exports as Cursor, Errors_exports as Errors, Format_exports as Format, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Maturity_exports as Maturity, MempoolClient_exports as Mempool, Obligation_exports as Obligation, Offer_exports as Offer, Quote_exports as Quote, Schema_exports as RouterApi, Client_exports as RouterClient, time_exports as Time, utils_exports as Utils, Validation_exports as Validation, ValidationRule_exports as ValidationRule };
2433
2640
  //# sourceMappingURL=index.browser.mjs.map
2434
2641
  //# sourceMappingURL=index.browser.mjs.map