@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.
@@ -2,12 +2,12 @@
2
2
 
3
3
  var v4 = require('zod/v4');
4
4
  var viem = require('viem');
5
+ var zodOpenapi = require('zod-openapi');
5
6
  var actions = require('viem/actions');
6
7
  var chains$1 = require('viem/chains');
7
8
  var z7 = require('zod');
8
- var jsBase64 = require('js-base64');
9
9
  var accounts = require('viem/accounts');
10
- var zodOpenapi = require('zod-openapi');
10
+ var jsBase64 = require('js-base64');
11
11
 
12
12
  function _interopNamespace(e) {
13
13
  if (e && e.__esModule) return e;
@@ -37,7 +37,7 @@ var __export = (target, all) => {
37
37
  };
38
38
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
39
39
 
40
- // src/api/Api/Schema/index.ts
40
+ // src/api/Schema/index.ts
41
41
  var Schema_exports = {};
42
42
  __export(Schema_exports, {
43
43
  ChainHealth: () => ChainHealth,
@@ -59,26 +59,88 @@ var CollectorHealth = v4.z.object({
59
59
  lag: v4.z.number().nullable(),
60
60
  status: v4.z.enum(["live", "lagging", "unknown"])
61
61
  });
62
- var CollectorsHealthResponse = v4.z.object({
63
- collectors: v4.z.array(CollectorHealth)
64
- });
62
+ var CollectorsHealthResponse = v4.z.array(CollectorHealth);
65
63
  var ChainHealth = v4.z.object({
66
64
  chain_id: v4.z.number(),
67
65
  block_number: v4.z.number(),
68
66
  updated_at: v4.z.string()
69
67
  });
70
- var ChainsHealthResponse = v4.z.object({
71
- chains: v4.z.array(ChainHealth)
72
- });
68
+ var ChainsHealthResponse = v4.z.array(ChainHealth);
73
69
  var RouterStatusResponse = v4.z.object({
74
70
  status: v4.z.enum(["live", "syncing"])
75
71
  });
76
72
 
77
- // src/api/Api/Schema/ObligationResponse.ts
73
+ // src/api/Schema/ObligationResponse.ts
78
74
  var ObligationResponse_exports = {};
79
75
  __export(ObligationResponse_exports, {
80
- from: () => from6
76
+ from: () => from
77
+ });
78
+
79
+ // src/utils/Format.ts
80
+ var Format_exports = {};
81
+ __export(Format_exports, {
82
+ fromSnakeCase: () => fromSnakeCase,
83
+ toSnakeCase: () => toSnakeCase
84
+ });
85
+ function toSnakeCase(obj) {
86
+ return stringifyBigint(
87
+ processObject(
88
+ obj,
89
+ (s) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`),
90
+ (value) => typeof value === "string" && viem.isAddress(value.toLowerCase()) ? viem.getAddress(value.toLowerCase()) : value
91
+ )
92
+ );
93
+ }
94
+ function fromSnakeCase(obj) {
95
+ return processObject(
96
+ obj,
97
+ (s) => viem.isAddress(s.toLowerCase()) ? s : s.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),
98
+ (value) => typeof value === "string" && viem.isAddress(value.toLowerCase()) ? value.toLowerCase() : value
99
+ );
100
+ }
101
+ function processObject(obj, fnKey, fnValue) {
102
+ if (typeof obj !== "object" || obj === null) return obj;
103
+ if (Array.isArray(obj)) return obj.map((item) => processObject(item, fnKey, fnValue));
104
+ return Object.entries(obj).reduce(
105
+ (acc, [key, value]) => {
106
+ const newKey = fnKey(key);
107
+ acc[newKey] = typeof value === "object" && value !== null ? processObject(value, fnKey, fnValue) : fnValue(value);
108
+ return acc;
109
+ },
110
+ {}
111
+ );
112
+ }
113
+ function stringifyBigint(value) {
114
+ if (typeof value === "bigint") return value.toString();
115
+ if (Array.isArray(value)) return value.map(stringifyBigint);
116
+ if (value && typeof value === "object") {
117
+ const out = {};
118
+ for (const [k, v] of Object.entries(value)) {
119
+ out[k] = stringifyBigint(v);
120
+ }
121
+ return out;
122
+ }
123
+ return value;
124
+ }
125
+
126
+ // src/api/Schema/ObligationResponse.ts
127
+ function from(obligation, quote) {
128
+ return toSnakeCase({
129
+ id: quote.obligationId,
130
+ ...obligation,
131
+ ask: quote.ask,
132
+ bid: quote.bid
133
+ });
134
+ }
135
+
136
+ // src/api/Schema/OfferResponse.ts
137
+ var OfferResponse_exports = {};
138
+ __export(OfferResponse_exports, {
139
+ from: () => from2
81
140
  });
141
+ function from2(offer) {
142
+ return toSnakeCase(offer);
143
+ }
82
144
 
83
145
  // src/core/Abi.ts
84
146
  var Abi_exports = {};
@@ -447,8 +509,12 @@ var chains = {
447
509
  [
448
510
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
449
511
  // USDC
450
- "0x6B175474E89094C44Da98b954EedeAC495271d0F"
512
+ "0x6B175474E89094C44Da98b954EedeAC495271d0F",
451
513
  // DAI
514
+ "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
515
+ // WETH
516
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
517
+ // WBTC
452
518
  ].map((address) => address.toLowerCase())
453
519
  ),
454
520
  morpho: "0x0000000000000000000000000000000000000000",
@@ -471,8 +537,12 @@ var chains = {
471
537
  [
472
538
  "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
473
539
  // USDC
474
- "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb"
540
+ "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
475
541
  // DAI
542
+ "0x4200000000000000000000000000000000000006",
543
+ // WETH
544
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
545
+ // WBTC
476
546
  ].map((address) => address.toLowerCase())
477
547
  ),
478
548
  morpho: "0x0000000000000000000000000000000000000000",
@@ -495,8 +565,12 @@ var chains = {
495
565
  [
496
566
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
497
567
  // USDC
498
- "0x6B175474E89094C44Da98b954EedeAC495271d0F"
568
+ "0x6B175474E89094C44Da98b954EedeAC495271d0F",
499
569
  // DAI
570
+ "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
571
+ // WETH
572
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
573
+ // WBTC
500
574
  ].map((address) => address.toLowerCase())
501
575
  ),
502
576
  morpho: "0x11a002d45db720ed47a80d2f3489cba5b833eaf5",
@@ -520,8 +594,12 @@ var chains = {
520
594
  [
521
595
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
522
596
  // USDC
523
- "0x6B175474E89094C44Da98b954EedeAC495271d0F"
597
+ "0x6B175474E89094C44Da98b954EedeAC495271d0F",
524
598
  // DAI
599
+ "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
600
+ // WETH
601
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
602
+ // WBTC
525
603
  ].map((address) => address.toLowerCase())
526
604
  ),
527
605
  morpho: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
@@ -649,7 +727,7 @@ var Collateral_exports = {};
649
727
  __export(Collateral_exports, {
650
728
  CollateralSchema: () => CollateralSchema,
651
729
  CollateralsSchema: () => CollateralsSchema,
652
- from: () => from2
730
+ from: () => from4
653
731
  });
654
732
  var transformHex = (val, ctx) => {
655
733
  if (viem.isHex(val)) return val;
@@ -679,11 +757,11 @@ __export(LLTV_exports, {
679
757
  InvalidOptionError: () => InvalidOptionError,
680
758
  LLTVSchema: () => LLTVSchema,
681
759
  Options: () => Options,
682
- from: () => from
760
+ from: () => from3
683
761
  });
684
762
  var Options = [0.385, 0.5, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965, 0.98];
685
763
  var LLTV_SCALED = Options.map((lltv) => BigInt(lltv * 10 ** 18));
686
- function from(lltv) {
764
+ function from3(lltv) {
687
765
  if (typeof lltv === "bigint" && !LLTV_SCALED.includes(lltv)) throw new InvalidLLTVError(lltv);
688
766
  if (typeof lltv === "bigint") return lltv;
689
767
  if (typeof lltv === "number" && !Options.includes(lltv)) throw new InvalidOptionError(lltv);
@@ -712,7 +790,7 @@ var InvalidLLTVError = class extends BaseError {
712
790
  var LLTVSchema = z7__namespace.bigint({ coerce: true }).refine(
713
791
  (lltv) => {
714
792
  try {
715
- from(lltv);
793
+ from3(lltv);
716
794
  return true;
717
795
  } catch (_) {
718
796
  return false;
@@ -723,7 +801,7 @@ var LLTVSchema = z7__namespace.bigint({ coerce: true }).refine(
723
801
  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)";
724
802
  }
725
803
  }
726
- ).transform((lltv) => from(lltv));
804
+ ).transform((lltv) => from3(lltv));
727
805
 
728
806
  // src/core/Collateral.ts
729
807
  var CollateralSchema = z7__namespace.object({
@@ -759,105 +837,14 @@ var CollateralsSchema = z7__namespace.array(CollateralSchema).min(1, { message:
759
837
  message: "Collaterals must not contain duplicate assets"
760
838
  }
761
839
  );
762
- var from2 = (parameters) => {
840
+ var from4 = (parameters) => {
763
841
  return {
764
842
  asset: parameters.asset.toLowerCase(),
765
- lltv: from(parameters.lltv),
843
+ lltv: from3(parameters.lltv),
766
844
  oracle: parameters.oracle.toLowerCase()
767
845
  };
768
846
  };
769
847
 
770
- // src/core/Cursor.ts
771
- var Cursor_exports = {};
772
- __export(Cursor_exports, {
773
- decode: () => decode,
774
- encode: () => encode,
775
- validate: () => validate
776
- });
777
- function validate(cursor) {
778
- if (!cursor || typeof cursor !== "object") {
779
- throw new Error("Cursor must be an object");
780
- }
781
- const c = cursor;
782
- if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
783
- throw new Error(
784
- `Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
785
- );
786
- }
787
- if (!["asc", "desc"].includes(c.dir)) {
788
- throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
789
- }
790
- if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
791
- throw new Error(
792
- `Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
793
- );
794
- }
795
- const validations = {
796
- rate: {
797
- field: "rate",
798
- type: "string",
799
- pattern: /^\d+$/,
800
- error: "numeric string"
801
- },
802
- amount: {
803
- field: "assets",
804
- type: "string",
805
- pattern: /^\d+$/,
806
- error: "numeric string"
807
- },
808
- maturity: {
809
- field: "maturity",
810
- type: "number",
811
- validator: (val) => val > 0,
812
- error: "positive number"
813
- },
814
- expiry: {
815
- field: "expiry",
816
- type: "number",
817
- validator: (val) => val > 0,
818
- error: "positive number"
819
- }
820
- };
821
- const validation = validations[c.sort];
822
- if (!validation) {
823
- throw new Error(`Invalid sort field: ${c.sort}`);
824
- }
825
- const fieldValue = c[validation.field];
826
- if (!fieldValue) {
827
- throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
828
- }
829
- if (typeof fieldValue !== validation.type) {
830
- throw new Error(
831
- `${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
832
- );
833
- }
834
- if (validation.pattern && !validation.pattern.test(fieldValue)) {
835
- throw new Error(
836
- `Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
837
- );
838
- }
839
- if (validation.validator && !validation.validator(fieldValue)) {
840
- throw new Error(
841
- `Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
842
- );
843
- }
844
- if (c.page !== void 0) {
845
- if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
846
- throw new Error("Invalid page: must be a positive integer");
847
- }
848
- }
849
- return true;
850
- }
851
- function encode(c) {
852
- return jsBase64.Base64.encodeURL(JSON.stringify(c));
853
- }
854
- function decode(token) {
855
- if (!token) return null;
856
- const decoded = JSON.parse(jsBase64.Base64.decode(token));
857
- validate(decoded);
858
- return decoded;
859
- }
860
-
861
848
  // src/core/Liquidity.ts
862
849
  var Liquidity_exports = {};
863
850
  __export(Liquidity_exports, {
@@ -923,12 +910,12 @@ __export(Maturity_exports, {
923
910
  InvalidFormatError: () => InvalidFormatError,
924
911
  InvalidOptionError: () => InvalidOptionError2,
925
912
  MaturitySchema: () => MaturitySchema,
926
- from: () => from3
913
+ from: () => from5
927
914
  });
928
915
  var MaturitySchema = z7__namespace.number().int().refine(
929
916
  (maturity) => {
930
917
  try {
931
- from3(maturity);
918
+ from5(maturity);
932
919
  return true;
933
920
  } catch (_e) {
934
921
  return false;
@@ -953,7 +940,7 @@ var MaturityOptions = {
953
940
  end_of_quarter: () => endOfQuarter(),
954
941
  end_of_next_quarter: () => endOfNextQuarter()
955
942
  };
956
- function from3(ts) {
943
+ function from5(ts) {
957
944
  if (typeof ts === "string") {
958
945
  if (ts in MaturityOptions) return MaturityOptions[ts]();
959
946
  throw new InvalidOptionError2(ts);
@@ -1031,71 +1018,22 @@ __export(Obligation_exports, {
1031
1018
  CollateralsAreNotSortedError: () => CollateralsAreNotSortedError,
1032
1019
  InvalidObligationError: () => InvalidObligationError,
1033
1020
  ObligationSchema: () => ObligationSchema,
1034
- from: () => from4,
1021
+ from: () => from6,
1035
1022
  fromSnakeCase: () => fromSnakeCase2,
1036
1023
  id: () => id,
1037
1024
  random: () => random
1038
1025
  });
1039
-
1040
- // src/utils/Format.ts
1041
- var Format_exports = {};
1042
- __export(Format_exports, {
1043
- fromSnakeCase: () => fromSnakeCase,
1044
- toSnakeCase: () => toSnakeCase
1045
- });
1046
- function toSnakeCase(obj) {
1047
- return stringifyBigint(
1048
- processObject(
1049
- obj,
1050
- (s) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`),
1051
- (value) => typeof value === "string" && viem.isAddress(value.toLowerCase()) ? viem.getAddress(value.toLowerCase()) : value
1052
- )
1053
- );
1054
- }
1055
- function fromSnakeCase(obj) {
1056
- return processObject(
1057
- obj,
1058
- (s) => viem.isAddress(s.toLowerCase()) ? s : s.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),
1059
- (value) => typeof value === "string" && viem.isAddress(value.toLowerCase()) ? value.toLowerCase() : value
1060
- );
1061
- }
1062
- function processObject(obj, fnKey, fnValue) {
1063
- if (typeof obj !== "object" || obj === null) return obj;
1064
- if (Array.isArray(obj)) return obj.map((item) => processObject(item, fnKey, fnValue));
1065
- return Object.entries(obj).reduce(
1066
- (acc, [key, value]) => {
1067
- const newKey = fnKey(key);
1068
- acc[newKey] = typeof value === "object" && value !== null ? processObject(value, fnKey, fnValue) : fnValue(value);
1069
- return acc;
1070
- },
1071
- {}
1072
- );
1073
- }
1074
- function stringifyBigint(value) {
1075
- if (typeof value === "bigint") return value.toString();
1076
- if (Array.isArray(value)) return value.map(stringifyBigint);
1077
- if (value && typeof value === "object") {
1078
- const out = {};
1079
- for (const [k, v] of Object.entries(value)) {
1080
- out[k] = stringifyBigint(v);
1081
- }
1082
- return out;
1083
- }
1084
- return value;
1085
- }
1086
-
1087
- // src/core/Obligation.ts
1088
1026
  var ObligationSchema = z7__namespace.object({
1089
1027
  chainId: z7__namespace.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
1090
1028
  loanToken: z7__namespace.string().transform(transformAddress),
1091
1029
  collaterals: CollateralsSchema,
1092
1030
  maturity: MaturitySchema
1093
1031
  });
1094
- function from4(parameters) {
1032
+ function from6(parameters) {
1095
1033
  try {
1096
1034
  const parsedObligation = ObligationSchema.parse({
1097
1035
  ...parameters,
1098
- maturity: from3(parameters.maturity)
1036
+ maturity: from5(parameters.maturity)
1099
1037
  });
1100
1038
  return {
1101
1039
  chainId: parsedObligation.chainId,
@@ -1108,7 +1046,7 @@ function from4(parameters) {
1108
1046
  }
1109
1047
  }
1110
1048
  function fromSnakeCase2(input) {
1111
- return from4(fromSnakeCase(input));
1049
+ return from6(fromSnakeCase(input));
1112
1050
  }
1113
1051
  function id(obligation) {
1114
1052
  let lastAsset = "";
@@ -1146,17 +1084,17 @@ function id(obligation) {
1146
1084
  );
1147
1085
  }
1148
1086
  function random() {
1149
- return from4({
1087
+ return from6({
1150
1088
  chainId: 1n,
1151
1089
  loanToken: accounts.privateKeyToAccount(accounts.generatePrivateKey()).address,
1152
1090
  collaterals: [
1153
- from2({
1091
+ from4({
1154
1092
  asset: accounts.privateKeyToAccount(accounts.generatePrivateKey()).address,
1155
1093
  oracle: accounts.privateKeyToAccount(accounts.generatePrivateKey()).address,
1156
1094
  lltv: 0.965
1157
1095
  })
1158
1096
  ],
1159
- maturity: from3("end_of_next_quarter")
1097
+ maturity: from5("end_of_next_quarter")
1160
1098
  });
1161
1099
  }
1162
1100
  var InvalidObligationError = class extends BaseError {
@@ -1180,10 +1118,10 @@ __export(Offer_exports, {
1180
1118
  OfferHashSchema: () => OfferHashSchema,
1181
1119
  OfferSchema: () => OfferSchema,
1182
1120
  consumedEvent: () => consumedEvent,
1183
- decode: () => decode2,
1121
+ decode: () => decode,
1184
1122
  domain: () => domain,
1185
- encode: () => encode2,
1186
- from: () => from5,
1123
+ encode: () => encode,
1124
+ from: () => from7,
1187
1125
  fromConsumedLog: () => fromConsumedLog,
1188
1126
  fromSnakeCase: () => fromSnakeCase3,
1189
1127
  hash: () => hash,
@@ -1352,7 +1290,7 @@ var OfferSchema = (parameters) => {
1352
1290
  path: ["expiry"]
1353
1291
  });
1354
1292
  };
1355
- function from5(input) {
1293
+ function from7(input) {
1356
1294
  try {
1357
1295
  const parsedOffer = OfferSchema({ omitHash: true }).parse(input);
1358
1296
  const parsedHash = OfferHashSchema.parse(hash(parsedOffer));
@@ -1365,44 +1303,97 @@ function from5(input) {
1365
1303
  }
1366
1304
  }
1367
1305
  function fromSnakeCase3(input) {
1368
- return from5(fromSnakeCase(input));
1306
+ return from7(fromSnakeCase(input));
1369
1307
  }
1370
1308
  function toSnakeCase2(offer) {
1371
1309
  return toSnakeCase(offer);
1372
1310
  }
1373
- function random2() {
1374
- const loanToken = accounts.privateKeyToAccount(accounts.generatePrivateKey()).address;
1375
- const maturity = from3("end_of_month");
1376
- const expiry = from3("end_of_week") - 1;
1377
- const lltv = from(0.965);
1378
- const offer = from5({
1379
- offering: accounts.privateKeyToAccount(accounts.generatePrivateKey()).address,
1380
- assets: BigInt(Math.floor(Math.random() * 1e6)),
1381
- rate: BigInt(Math.floor(Math.random() * 1e6)),
1311
+ function random2(config) {
1312
+ const chain = config?.chains ? config.chains[Math.floor(Math.random() * config.chains.length)] : chains.ethereum;
1313
+ const loanToken = config?.loanTokens ? config.loanTokens[Math.floor(Math.random() * config.loanTokens.length)] : accounts.privateKeyToAccount(accounts.generatePrivateKey()).address;
1314
+ const collateralCandidates = config?.collateralTokens ? config.collateralTokens.filter((a) => a !== loanToken) : [accounts.privateKeyToAccount(accounts.generatePrivateKey()).address];
1315
+ const collateralAsset = collateralCandidates[Math.floor(Math.random() * collateralCandidates.length)];
1316
+ const maturityOption = weightedChoice([
1317
+ ["end_of_month", 1],
1318
+ ["end_of_next_month", 1]
1319
+ ]);
1320
+ const maturity = config?.maturity ?? from5(maturityOption);
1321
+ const lltv = from3(
1322
+ weightedChoice([
1323
+ [0.385, 1],
1324
+ [0.5, 1],
1325
+ [0.625, 2],
1326
+ [0.77, 8],
1327
+ [0.86, 10],
1328
+ [0.915, 8],
1329
+ [0.945, 6],
1330
+ [0.965, 4],
1331
+ [0.98, 2]
1332
+ ])
1333
+ );
1334
+ const buy = config?.buy !== void 0 ? config.buy : Math.random() > 0.5;
1335
+ const ONE = 1000000000000000000n;
1336
+ const qMin = buy ? 16 : 4;
1337
+ const qMax = buy ? 32 : 16;
1338
+ const len = qMax - qMin + 1;
1339
+ const ratePairs = Array.from(
1340
+ { length: len },
1341
+ (_, idx) => {
1342
+ const q = qMin + idx;
1343
+ const scaledRate = BigInt(q) * (ONE / 4n);
1344
+ const weight = buy ? 1 + idx : 1 + (len - 1 - idx);
1345
+ return [scaledRate, weight];
1346
+ }
1347
+ );
1348
+ const rate = config?.rate ?? weightedChoice(ratePairs);
1349
+ const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
1350
+ const unit = BigInt(10) ** BigInt(loanTokenDecimals);
1351
+ const amountBase = BigInt(100 + Math.floor(Math.random() * (1e6 - 100 + 1)));
1352
+ const assetsScaled = config?.assets ?? amountBase * unit;
1353
+ const consumed = config?.consumed !== void 0 ? config.consumed : Math.random() < 0.8 ? 0n : assetsScaled * BigInt(1 + Math.floor(Math.random() * 900)) / 1000n;
1354
+ const callbackBySide = (() => {
1355
+ if (buy) return { address: viem.zeroAddress, data: "0x", gasLimit: 0n };
1356
+ const sellCallbackAddress = WhitelistedCallbackAddresses["sell_erc20_callback" /* SellERC20Callback */][0].toLowerCase();
1357
+ const amount = assetsScaled * 1000000000000000000000n;
1358
+ const data = encodeSellERC20Callback({
1359
+ collaterals: [collateralAsset],
1360
+ amounts: [amount]
1361
+ });
1362
+ return { address: sellCallbackAddress, data, gasLimit: 500000n };
1363
+ })();
1364
+ const offer = from7({
1365
+ offering: config?.offering ?? accounts.privateKeyToAccount(accounts.generatePrivateKey()).address,
1366
+ assets: assetsScaled,
1367
+ rate,
1382
1368
  maturity,
1383
- expiry,
1384
- start: expiry - 10,
1369
+ expiry: config?.expiry ?? maturity - 1,
1370
+ start: config?.start ?? maturity - 10,
1385
1371
  nonce: BigInt(Math.floor(Math.random() * 1e6)),
1386
- buy: Math.random() > 0.5,
1387
- chainId: 1n,
1372
+ buy,
1373
+ chainId: chain.id,
1388
1374
  loanToken,
1389
- collaterals: [
1390
- from2({
1391
- asset: viem.zeroAddress,
1375
+ collaterals: config?.collaterals ?? [
1376
+ from4({
1377
+ asset: collateralAsset,
1392
1378
  oracle: viem.zeroAddress,
1393
1379
  lltv
1394
1380
  })
1395
1381
  ],
1396
- callback: {
1397
- address: viem.zeroAddress,
1398
- data: "0x",
1399
- gasLimit: 0n
1400
- },
1401
- consumed: 0n,
1382
+ callback: config?.callback ?? callbackBySide,
1383
+ consumed,
1402
1384
  blockNumber: Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
1403
1385
  });
1404
1386
  return offer;
1405
1387
  }
1388
+ var weightedChoice = (pairs) => {
1389
+ const total = pairs.reduce((sum, [, weight]) => sum + weight, 0);
1390
+ let roll = Math.random() * total;
1391
+ for (const [value, weight] of pairs) {
1392
+ roll -= weight;
1393
+ if (roll < 0) return value;
1394
+ }
1395
+ return pairs[0][0];
1396
+ };
1406
1397
  var domain = (chainId) => ({
1407
1398
  chainId,
1408
1399
  verifyingContract: viem.zeroAddress
@@ -1485,7 +1476,7 @@ function hash(offer) {
1485
1476
  }
1486
1477
  function obligationId(offer) {
1487
1478
  return id(
1488
- from4({
1479
+ from6({
1489
1480
  chainId: offer.chainId,
1490
1481
  loanToken: offer.loanToken,
1491
1482
  collaterals: offer.collaterals,
@@ -1524,7 +1515,7 @@ var OfferAbi = [
1524
1515
  },
1525
1516
  { name: "signature", type: "bytes" }
1526
1517
  ];
1527
- function encode2(offer) {
1518
+ function encode(offer) {
1528
1519
  return viem.encodeAbiParameters(OfferAbi, [
1529
1520
  offer.offering,
1530
1521
  offer.assets,
@@ -1541,18 +1532,18 @@ function encode2(offer) {
1541
1532
  offer.signature ?? "0x"
1542
1533
  ]);
1543
1534
  }
1544
- function decode2(data, blockNumber) {
1535
+ function decode(data, blockNumber) {
1545
1536
  let decoded;
1546
1537
  try {
1547
1538
  decoded = viem.decodeAbiParameters(OfferAbi, data);
1548
1539
  } catch (error) {
1549
1540
  throw new InvalidOfferError(error);
1550
1541
  }
1551
- const offer = from5({
1542
+ const offer = from7({
1552
1543
  offering: decoded[0],
1553
1544
  assets: decoded[1],
1554
1545
  rate: decoded[2],
1555
- maturity: from3(Number(decoded[3])),
1546
+ maturity: from5(Number(decoded[3])),
1556
1547
  expiry: Number(decoded[4]),
1557
1548
  nonce: decoded[5],
1558
1549
  buy: decoded[6],
@@ -1560,7 +1551,7 @@ function decode2(data, blockNumber) {
1560
1551
  loanToken: decoded[8],
1561
1552
  start: Number(decoded[9]),
1562
1553
  collaterals: decoded[10].map((c) => {
1563
- return from2({
1554
+ return from4({
1564
1555
  asset: c.asset,
1565
1556
  oracle: c.oracle,
1566
1557
  lltv: c.lltv
@@ -1611,22 +1602,152 @@ var AccountNotSetError = class extends BaseError {
1611
1602
  }
1612
1603
  };
1613
1604
 
1605
+ // src/core/Quote.ts
1606
+ var Quote_exports = {};
1607
+ __export(Quote_exports, {
1608
+ InvalidQuoteError: () => InvalidQuoteError,
1609
+ QuoteSchema: () => QuoteSchema,
1610
+ from: () => from8,
1611
+ fromSnakeCase: () => fromSnakeCase4,
1612
+ random: () => random3
1613
+ });
1614
+ var QuoteSchema = z7__namespace.object({
1615
+ obligationId: z7__namespace.string().transform(transformHex),
1616
+ ask: z7__namespace.object({
1617
+ rate: z7__namespace.bigint({ coerce: true }).min(0n).max(viem.maxUint256)
1618
+ }),
1619
+ bid: z7__namespace.object({
1620
+ rate: z7__namespace.bigint({ coerce: true }).min(0n).max(viem.maxUint256)
1621
+ })
1622
+ });
1623
+ function from8(parameters) {
1624
+ try {
1625
+ const parsedQuote = QuoteSchema.parse(parameters);
1626
+ return {
1627
+ obligationId: parsedQuote.obligationId,
1628
+ ask: parsedQuote.ask,
1629
+ bid: parsedQuote.bid
1630
+ };
1631
+ } catch (error) {
1632
+ throw new InvalidQuoteError(error);
1633
+ }
1634
+ }
1635
+ function fromSnakeCase4(snake) {
1636
+ return from8(fromSnakeCase(snake));
1637
+ }
1638
+ function random3() {
1639
+ return from8({
1640
+ obligationId: Obligation_exports.id(Obligation_exports.random()),
1641
+ ask: {
1642
+ rate: BigInt(Math.floor(Math.random() * 1e6))
1643
+ },
1644
+ bid: {
1645
+ rate: BigInt(Math.floor(Math.random() * 1e6))
1646
+ }
1647
+ });
1648
+ }
1649
+ var InvalidQuoteError = class extends BaseError {
1650
+ constructor(error) {
1651
+ super("Invalid quote.", { cause: error });
1652
+ __publicField(this, "name", "Quote.InvalidQuoteError");
1653
+ }
1654
+ };
1655
+
1614
1656
  // src/core/types.ts
1615
1657
  var BrandTypeId = Symbol.for("mempool/Brand");
1616
1658
 
1617
- // src/api/Api/Schema/ObligationResponse.ts
1618
- function from6(obligation) {
1619
- return toSnakeCase({ id: Obligation_exports.id(obligation), ...obligation });
1620
- }
1621
-
1622
- // src/api/Api/Schema/OfferResponse.ts
1623
- var OfferResponse_exports = {};
1624
- __export(OfferResponse_exports, {
1625
- from: () => from7
1659
+ // src/stores/utils/Cursor.ts
1660
+ var Cursor_exports = {};
1661
+ __export(Cursor_exports, {
1662
+ decode: () => decode2,
1663
+ encode: () => encode2,
1664
+ validate: () => validate
1626
1665
  });
1627
- function from7(offer) {
1628
- return toSnakeCase(offer);
1666
+ function validate(cursor) {
1667
+ if (!cursor || typeof cursor !== "object") {
1668
+ throw new Error("Cursor must be an object");
1669
+ }
1670
+ const c = cursor;
1671
+ if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
1672
+ throw new Error(
1673
+ `Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
1674
+ );
1675
+ }
1676
+ if (!["asc", "desc"].includes(c.dir)) {
1677
+ throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
1678
+ }
1679
+ if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
1680
+ throw new Error(
1681
+ `Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
1682
+ );
1683
+ }
1684
+ const validations = {
1685
+ rate: {
1686
+ field: "rate",
1687
+ type: "string",
1688
+ pattern: /^\d+$/,
1689
+ error: "numeric string"
1690
+ },
1691
+ amount: {
1692
+ field: "assets",
1693
+ type: "string",
1694
+ pattern: /^\d+$/,
1695
+ error: "numeric string"
1696
+ },
1697
+ maturity: {
1698
+ field: "maturity",
1699
+ type: "number",
1700
+ validator: (val) => val > 0,
1701
+ error: "positive number"
1702
+ },
1703
+ expiry: {
1704
+ field: "expiry",
1705
+ type: "number",
1706
+ validator: (val) => val > 0,
1707
+ error: "positive number"
1708
+ }
1709
+ };
1710
+ const validation = validations[c.sort];
1711
+ if (!validation) {
1712
+ throw new Error(`Invalid sort field: ${c.sort}`);
1713
+ }
1714
+ const fieldValue = c[validation.field];
1715
+ if (!fieldValue) {
1716
+ throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
1717
+ }
1718
+ if (typeof fieldValue !== validation.type) {
1719
+ throw new Error(
1720
+ `${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
1721
+ );
1722
+ }
1723
+ if (validation.pattern && !validation.pattern.test(fieldValue)) {
1724
+ throw new Error(
1725
+ `Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
1726
+ );
1727
+ }
1728
+ if (validation.validator && !validation.validator(fieldValue)) {
1729
+ throw new Error(
1730
+ `Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
1731
+ );
1732
+ }
1733
+ if (c.page !== void 0) {
1734
+ if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
1735
+ throw new Error("Invalid page: must be a positive integer");
1736
+ }
1737
+ }
1738
+ return true;
1739
+ }
1740
+ function encode2(c) {
1741
+ return jsBase64.Base64.encodeURL(JSON.stringify(c));
1742
+ }
1743
+ function decode2(token) {
1744
+ if (!token) return null;
1745
+ const decoded = JSON.parse(jsBase64.Base64.decode(token));
1746
+ validate(decoded);
1747
+ return decoded;
1629
1748
  }
1749
+
1750
+ // src/api/Schema/requests.ts
1630
1751
  var MAX_LIMIT = 100;
1631
1752
  var DEFAULT_LIMIT = 20;
1632
1753
  var PaginationQueryParams = z7__namespace.object({
@@ -1689,14 +1810,74 @@ function safeParse(action, query, error) {
1689
1810
  });
1690
1811
  }
1691
1812
 
1692
- // src/api/Api/Schema/openapi.ts
1693
- var successResponseSchema = v4.z.object({
1694
- status: v4.z.literal("success"),
1695
- cursor: v4.z.string().nullable(),
1696
- data: v4.z.array(v4.z.any()),
1697
- meta: v4.z.object({
1698
- timestamp: v4.z.string()
1699
- })
1813
+ // src/api/Schema/openapi.ts
1814
+ var timestampExample = "2024-01-01T12:00:00.000Z";
1815
+ var cursorExample = "eyJvZmZzZXQiOjEwMH0";
1816
+ function makeSuccessResponse(parameters) {
1817
+ const { dataSchema, dataDescription, dataExample, cursor } = parameters;
1818
+ const withDataMeta = dataDescription ? dataSchema.meta({ description: dataDescription }) : dataSchema;
1819
+ return v4.z.object({
1820
+ status: v4.z.literal("success"),
1821
+ cursor: v4.z.string().nullable(),
1822
+ data: v4.z.any(),
1823
+ meta: v4.z.object({
1824
+ timestamp: v4.z.string()
1825
+ })
1826
+ }).extend({
1827
+ data: withDataMeta
1828
+ }).meta({
1829
+ example: {
1830
+ status: "success",
1831
+ cursor,
1832
+ data: dataExample,
1833
+ meta: { timestamp: timestampExample }
1834
+ }
1835
+ });
1836
+ }
1837
+ var OffersSuccessResponseSchema = makeSuccessResponse({
1838
+ dataSchema: v4.z.array(v4.z.any()),
1839
+ dataDescription: "Offers matching the provided filters.",
1840
+ dataExample: [toSnakeCase(Offer_exports.random())],
1841
+ cursor: cursorExample
1842
+ });
1843
+ var ObligationsSuccessResponseSchema = makeSuccessResponse({
1844
+ dataSchema: v4.z.array(v4.z.any()),
1845
+ dataDescription: "Obligations known to the router.",
1846
+ dataExample: [toSnakeCase(Obligation_exports.random())],
1847
+ cursor: cursorExample
1848
+ });
1849
+ var RouterStatusSuccessResponseSchema = makeSuccessResponse({
1850
+ dataSchema: RouterStatusResponse,
1851
+ dataDescription: "Aggregated router status.",
1852
+ dataExample: { status: "live" },
1853
+ cursor: null
1854
+ });
1855
+ var CollectorsHealthSuccessResponseSchema = makeSuccessResponse({
1856
+ dataSchema: CollectorsHealthResponse,
1857
+ dataDescription: "Collectors health details and sync status.",
1858
+ dataExample: [
1859
+ {
1860
+ name: "mempool_offers",
1861
+ chain_id: "1",
1862
+ block_number: 21345678,
1863
+ updated_at: "2024-01-01T12:00:00.000Z",
1864
+ lag: 0,
1865
+ status: "live"
1866
+ }
1867
+ ],
1868
+ cursor: null
1869
+ });
1870
+ var ChainsHealthSuccessResponseSchema = makeSuccessResponse({
1871
+ dataSchema: ChainsHealthResponse,
1872
+ dataDescription: "Latest processed block per chain.",
1873
+ dataExample: [
1874
+ {
1875
+ chain_id: "1",
1876
+ block_number: 21345678,
1877
+ updated_at: "2024-01-01T12:00:00.000Z"
1878
+ }
1879
+ ],
1880
+ cursor: null
1700
1881
  });
1701
1882
  var errorResponseSchema = v4.z.object({
1702
1883
  status: v4.z.literal("error"),
@@ -1708,6 +1889,24 @@ var errorResponseSchema = v4.z.object({
1708
1889
  meta: v4.z.object({
1709
1890
  timestamp: v4.z.string()
1710
1891
  })
1892
+ }).meta({
1893
+ description: "Error response wrapper.",
1894
+ example: {
1895
+ status: "error",
1896
+ error: {
1897
+ code: "VALIDATION_ERROR",
1898
+ message: "Invalid cursor format. Must be a valid base64url-encoded cursor object",
1899
+ details: [
1900
+ {
1901
+ field: "cursor",
1902
+ issue: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
1903
+ }
1904
+ ]
1905
+ },
1906
+ meta: {
1907
+ timestamp: timestampExample
1908
+ }
1909
+ }
1711
1910
  });
1712
1911
  var paths = {
1713
1912
  "/v1/offers": {
@@ -1723,7 +1922,7 @@ var paths = {
1723
1922
  description: "Success",
1724
1923
  content: {
1725
1924
  "application/json": {
1726
- schema: successResponseSchema
1925
+ schema: OffersSuccessResponseSchema
1727
1926
  }
1728
1927
  }
1729
1928
  },
@@ -1751,7 +1950,7 @@ var paths = {
1751
1950
  description: "Success",
1752
1951
  content: {
1753
1952
  "application/json": {
1754
- schema: successResponseSchema
1953
+ schema: ObligationsSuccessResponseSchema
1755
1954
  }
1756
1955
  }
1757
1956
  },
@@ -1776,7 +1975,7 @@ var paths = {
1776
1975
  description: "Success",
1777
1976
  content: {
1778
1977
  "application/json": {
1779
- schema: RouterStatusResponse
1978
+ schema: RouterStatusSuccessResponseSchema
1780
1979
  }
1781
1980
  }
1782
1981
  }
@@ -1793,7 +1992,7 @@ var paths = {
1793
1992
  description: "Success",
1794
1993
  content: {
1795
1994
  "application/json": {
1796
- schema: CollectorsHealthResponse
1995
+ schema: CollectorsHealthSuccessResponseSchema
1797
1996
  }
1798
1997
  }
1799
1998
  }
@@ -1810,7 +2009,7 @@ var paths = {
1810
2009
  description: "Success",
1811
2010
  content: {
1812
2011
  "application/json": {
1813
- schema: ChainsHealthResponse
2012
+ schema: ChainsHealthSuccessResponseSchema
1814
2013
  }
1815
2014
  }
1816
2015
  }
@@ -1842,14 +2041,14 @@ var OpenApi = zodOpenapi.createDocument({
1842
2041
  description: "Production server"
1843
2042
  },
1844
2043
  {
1845
- url: "http://localhost:8081",
2044
+ url: "http://localhost:7891",
1846
2045
  description: "Local development server"
1847
2046
  }
1848
2047
  ],
1849
2048
  paths
1850
2049
  });
1851
2050
 
1852
- // src/api/Client.ts
2051
+ // src/client/Client.ts
1853
2052
  var Client_exports = {};
1854
2053
  __export(Client_exports, {
1855
2054
  HttpForbiddenError: () => HttpForbiddenError,
@@ -1904,8 +2103,16 @@ async function getObligations(config, parameters) {
1904
2103
  if (parameters?.limit !== void 0) {
1905
2104
  url.searchParams.set("limit", parameters.limit.toString());
1906
2105
  }
1907
- const { cursor: returnedCursor, data: obligationsSnake } = await getApi(config, url);
1908
- const obligations = obligationsSnake.map(Obligation_exports.fromSnakeCase);
2106
+ const { cursor: returnedCursor, data: items } = await getApi(config, url);
2107
+ const obligations = items.map((item) => {
2108
+ const obligation = Obligation_exports.fromSnakeCase(item);
2109
+ const { obligationId: _, ...returned } = {
2110
+ id: () => Obligation_exports.id(obligation),
2111
+ ...obligation,
2112
+ ...Quote_exports.fromSnakeCase({ obligation_id: item.id, ask: item.ask, bid: item.bid })
2113
+ };
2114
+ return returned;
2115
+ });
1909
2116
  return {
1910
2117
  cursor: returnedCursor,
1911
2118
  obligations
@@ -2303,7 +2510,7 @@ __export(MempoolClient_exports, {
2303
2510
  });
2304
2511
  var DEFAULT_BATCH_SIZE2 = 100;
2305
2512
  var DEFAULT_BLOCK_WINDOW2 = 100;
2306
- function from8(parameters) {
2513
+ function from9(parameters) {
2307
2514
  const config = {
2308
2515
  client: parameters.client,
2309
2516
  mempoolAddress: parameters.mempoolAddress,
@@ -2448,7 +2655,7 @@ var ChainIdMismatchError = class extends BaseError {
2448
2655
 
2449
2656
  // src/mempool/MempoolClient.ts
2450
2657
  function connect2(parameters) {
2451
- return from8(parameters);
2658
+ return from9(parameters);
2452
2659
  }
2453
2660
 
2454
2661
  exports.Abi = Abi_exports;
@@ -2465,6 +2672,7 @@ exports.Maturity = Maturity_exports;
2465
2672
  exports.Mempool = MempoolClient_exports;
2466
2673
  exports.Obligation = Obligation_exports;
2467
2674
  exports.Offer = Offer_exports;
2675
+ exports.Quote = Quote_exports;
2468
2676
  exports.RouterApi = Schema_exports;
2469
2677
  exports.RouterClient = Client_exports;
2470
2678
  exports.Time = time_exports;