@p2pdotme/sdk 1.0.5 → 1.1.1

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.
Files changed (66) hide show
  1. package/README.md +103 -41
  2. package/dist/country.cjs +9 -2
  3. package/dist/country.cjs.map +1 -1
  4. package/dist/country.d.cts +35 -10
  5. package/dist/country.d.ts +35 -10
  6. package/dist/country.mjs +6 -2
  7. package/dist/country.mjs.map +1 -1
  8. package/dist/fraud-engine.cjs +52 -48
  9. package/dist/fraud-engine.cjs.map +1 -1
  10. package/dist/fraud-engine.mjs +46 -42
  11. package/dist/fraud-engine.mjs.map +1 -1
  12. package/dist/index.cjs +4 -14
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +41 -36
  15. package/dist/index.d.ts +41 -36
  16. package/dist/index.mjs +4 -12
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/orders.cjs +5961 -0
  19. package/dist/orders.cjs.map +1 -0
  20. package/dist/orders.d.cts +620 -0
  21. package/dist/orders.d.ts +620 -0
  22. package/dist/orders.mjs +5911 -0
  23. package/dist/orders.mjs.map +1 -0
  24. package/dist/prices.cjs +1432 -0
  25. package/dist/prices.cjs.map +1 -0
  26. package/dist/prices.d.cts +109 -0
  27. package/dist/prices.d.ts +109 -0
  28. package/dist/prices.mjs +1404 -0
  29. package/dist/prices.mjs.map +1 -0
  30. package/dist/profile.cjs +899 -69
  31. package/dist/profile.cjs.map +1 -1
  32. package/dist/profile.d.cts +39 -27
  33. package/dist/profile.d.ts +39 -27
  34. package/dist/profile.mjs +892 -62
  35. package/dist/profile.mjs.map +1 -1
  36. package/dist/qr-parsers.cjs +88 -7
  37. package/dist/qr-parsers.cjs.map +1 -1
  38. package/dist/qr-parsers.d.cts +38 -16
  39. package/dist/qr-parsers.d.ts +38 -16
  40. package/dist/qr-parsers.mjs +88 -7
  41. package/dist/qr-parsers.mjs.map +1 -1
  42. package/dist/react.cjs +2955 -1105
  43. package/dist/react.cjs.map +1 -1
  44. package/dist/react.d.cts +384 -104
  45. package/dist/react.d.ts +384 -104
  46. package/dist/react.mjs +2841 -992
  47. package/dist/react.mjs.map +1 -1
  48. package/dist/zkkyc.cjs +405 -24
  49. package/dist/zkkyc.cjs.map +1 -1
  50. package/dist/zkkyc.d.cts +14 -9
  51. package/dist/zkkyc.d.ts +14 -9
  52. package/dist/zkkyc.mjs +405 -24
  53. package/dist/zkkyc.mjs.map +1 -1
  54. package/package.json +12 -12
  55. package/dist/order-routing.cjs +0 -888
  56. package/dist/order-routing.cjs.map +0 -1
  57. package/dist/order-routing.d.cts +0 -68
  58. package/dist/order-routing.d.ts +0 -68
  59. package/dist/order-routing.mjs +0 -860
  60. package/dist/order-routing.mjs.map +0 -1
  61. package/dist/payload.cjs +0 -3168
  62. package/dist/payload.cjs.map +0 -1
  63. package/dist/payload.d.cts +0 -147
  64. package/dist/payload.d.ts +0 -147
  65. package/dist/payload.mjs +0 -3124
  66. package/dist/payload.mjs.map +0 -1
package/dist/react.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { createContext, useContext, useEffect, useMemo, useRef } from "react";
3
3
 
4
4
  // src/fraud-engine/client.ts
5
- import { errAsync, ResultAsync } from "neverthrow";
5
+ import { errAsync, ResultAsync as ResultAsync2 } from "neverthrow";
6
6
 
7
7
  // src/lib/encoding.ts
8
8
  function hexToBytes(hex) {
@@ -35,48 +35,8 @@ function sleep(ms) {
35
35
  return new Promise((resolve) => setTimeout(resolve, ms));
36
36
  }
37
37
 
38
- // src/fraud-engine/device.ts
39
- function getBasicDeviceDetails() {
40
- const nav = typeof navigator !== "undefined" ? navigator : void 0;
41
- const win = typeof window !== "undefined" ? window : void 0;
42
- return {
43
- userAgent: nav?.userAgent ?? "",
44
- platform: nav?.platform ?? "",
45
- language: nav?.language ?? "",
46
- languages: nav ? Array.from(nav.languages) : [],
47
- screenWidth: win?.screen?.width ?? 0,
48
- screenHeight: win?.screen?.height ?? 0,
49
- devicePixelRatio: win?.devicePixelRatio ?? 1,
50
- timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone ?? "",
51
- timezoneOffset: (/* @__PURE__ */ new Date()).getTimezoneOffset(),
52
- cookiesEnabled: nav?.cookieEnabled ?? false,
53
- doNotTrack: nav?.doNotTrack ?? null,
54
- online: nav?.onLine ?? true,
55
- connectionType: nav?.connection?.effectiveType,
56
- deviceMemory: nav?.deviceMemory,
57
- hardwareConcurrency: nav?.hardwareConcurrency,
58
- touchSupport: nav ? "ontouchstart" in window : false,
59
- maxTouchPoints: nav?.maxTouchPoints ?? 0,
60
- vendor: nav?.vendor ?? "",
61
- appVersion: nav?.appVersion ?? "",
62
- colorDepth: win?.screen?.colorDepth ?? 0,
63
- pixelDepth: win?.screen?.pixelDepth ?? 0
64
- };
65
- }
66
- async function fetchIpAddress() {
67
- try {
68
- const response = await fetch("https://api.ipify.org?format=json");
69
- const data = await response.json();
70
- return data.ip;
71
- } catch {
72
- return void 0;
73
- }
74
- }
75
- async function getDeviceDetails(seonSession) {
76
- const basic = getBasicDeviceDetails();
77
- const ip = await fetchIpAddress();
78
- return { ...basic, ip, seonSession };
79
- }
38
+ // src/lib/subgraph.ts
39
+ import { ResultAsync } from "neverthrow";
80
40
 
81
41
  // src/validation/errors.validation.ts
82
42
  var SdkError = class extends Error {
@@ -97,7 +57,7 @@ import { err, ok } from "neverthrow";
97
57
  import { isAddress } from "viem";
98
58
  import { z } from "zod";
99
59
 
100
- // src/constants/currencies.constant.ts
60
+ // src/country/currency.ts
101
61
  var CURRENCY = {
102
62
  IDR: "IDR",
103
63
  INR: "INR",
@@ -110,17 +70,11 @@ var CURRENCY = {
110
70
  USD: "USD",
111
71
  COP: "COP"
112
72
  };
113
-
114
- // src/constants/orders.constant.ts
115
- var ORDER_TYPE = {
116
- BUY: 0,
117
- SELL: 1,
118
- PAY: 2
119
- };
73
+ var CURRENCY_CODES = Object.values(CURRENCY);
120
74
 
121
75
  // src/validation/schemas.validation.ts
122
76
  var ZodAddressSchema = z.string().refine((s) => isAddress(s), { message: "Invalid Ethereum address" });
123
- var ZodCurrencySchema = z.enum(Object.values(CURRENCY));
77
+ var ZodCurrencySchema = z.enum(CURRENCY_CODES);
124
78
  function validate(schema, data, toError) {
125
79
  const result = schema.safeParse(data);
126
80
  if (result.success) {
@@ -129,6 +83,132 @@ function validate(schema, data, toError) {
129
83
  return err(toError(z.prettifyError(result.error), result.error, data));
130
84
  }
131
85
 
86
+ // src/lib/subgraph.ts
87
+ var DEFAULT_TIMEOUT_MS = 1e4;
88
+ var MAX_RETRIES = 3;
89
+ var BACKOFF_MS = 500;
90
+ var SubgraphError = class extends SdkError {
91
+ constructor(message, options) {
92
+ super(message, options);
93
+ this.name = "SubgraphError";
94
+ }
95
+ };
96
+ function isTransient(error) {
97
+ if (error instanceof SubgraphError) {
98
+ if (error.code !== "HTTP_ERROR") return false;
99
+ const status = error.context?.status;
100
+ return typeof status === "number" && status >= 500;
101
+ }
102
+ if (error instanceof DOMException && error.name === "AbortError") return true;
103
+ if (error instanceof TypeError) return true;
104
+ return false;
105
+ }
106
+ function querySubgraph(url, params) {
107
+ const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;
108
+ const fetchOnce = async () => {
109
+ const controller = new AbortController();
110
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
111
+ try {
112
+ const response = await fetch(url, {
113
+ method: "POST",
114
+ headers: { "Content-Type": "application/json" },
115
+ body: JSON.stringify({
116
+ query: params.query,
117
+ variables: params.variables
118
+ }),
119
+ signal: controller.signal
120
+ });
121
+ if (!response.ok) {
122
+ throw new SubgraphError(`Subgraph request failed (status: ${response.status})`, {
123
+ code: "HTTP_ERROR",
124
+ cause: response,
125
+ context: { status: response.status }
126
+ });
127
+ }
128
+ const json = await response.json();
129
+ if (json.errors?.length > 0) {
130
+ throw new SubgraphError("Subgraph returned GraphQL errors", {
131
+ code: "GRAPHQL_ERROR",
132
+ cause: json.errors,
133
+ context: { errors: json.errors }
134
+ });
135
+ }
136
+ if (!json.data) {
137
+ throw new SubgraphError("Subgraph returned no data", {
138
+ code: "NO_DATA",
139
+ cause: "Missing data field in GraphQL response",
140
+ context: { response: json }
141
+ });
142
+ }
143
+ return json.data;
144
+ } finally {
145
+ clearTimeout(timer);
146
+ }
147
+ };
148
+ const fetchWithRetry = async () => {
149
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
150
+ try {
151
+ return await fetchOnce();
152
+ } catch (error) {
153
+ const lastAttempt = attempt === MAX_RETRIES;
154
+ if (lastAttempt || !isTransient(error)) throw error;
155
+ await sleep(BACKOFF_MS * (attempt + 1));
156
+ }
157
+ }
158
+ throw new SubgraphError("Subgraph query exhausted retries", { code: "TRANSPORT_ERROR" });
159
+ };
160
+ return ResultAsync.fromPromise(
161
+ fetchWithRetry(),
162
+ (error) => error instanceof SubgraphError ? error : new SubgraphError("Subgraph query failed", {
163
+ code: "TRANSPORT_ERROR",
164
+ cause: error
165
+ })
166
+ );
167
+ }
168
+
169
+ // src/fraud-engine/device.ts
170
+ function getBasicDeviceDetails() {
171
+ const nav = typeof navigator !== "undefined" ? navigator : void 0;
172
+ const win = typeof window !== "undefined" ? window : void 0;
173
+ return {
174
+ userAgent: nav?.userAgent ?? "",
175
+ platform: nav?.platform ?? "",
176
+ language: nav?.language ?? "",
177
+ languages: nav ? Array.from(nav.languages) : [],
178
+ screenWidth: win?.screen?.width ?? 0,
179
+ screenHeight: win?.screen?.height ?? 0,
180
+ devicePixelRatio: win?.devicePixelRatio ?? 1,
181
+ timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone ?? "",
182
+ timezoneOffset: (/* @__PURE__ */ new Date()).getTimezoneOffset(),
183
+ cookiesEnabled: nav?.cookieEnabled ?? false,
184
+ doNotTrack: nav?.doNotTrack ?? null,
185
+ online: nav?.onLine ?? true,
186
+ connectionType: nav?.connection?.effectiveType,
187
+ deviceMemory: nav?.deviceMemory,
188
+ hardwareConcurrency: nav?.hardwareConcurrency,
189
+ touchSupport: nav ? "ontouchstart" in window : false,
190
+ maxTouchPoints: nav?.maxTouchPoints ?? 0,
191
+ vendor: nav?.vendor ?? "",
192
+ appVersion: nav?.appVersion ?? "",
193
+ colorDepth: win?.screen?.colorDepth ?? 0,
194
+ pixelDepth: win?.screen?.pixelDepth ?? 0
195
+ };
196
+ }
197
+ async function fetchIpAddress() {
198
+ try {
199
+ const response = await fetch("https://api.ipify.org?format=json");
200
+ const data = await response.json();
201
+ return data.ip;
202
+ } catch {
203
+ return void 0;
204
+ }
205
+ }
206
+ async function getDeviceDetails(seonSession) {
207
+ const basic = getBasicDeviceDetails();
208
+ const ip = await fetchIpAddress();
209
+ return { ...basic, ip, seonSession };
210
+ }
211
+
132
212
  // src/fraud-engine/errors.ts
133
213
  var FraudEngineError = class extends SdkError {
134
214
  constructor(message, options) {
@@ -320,7 +400,7 @@ function createFraudEngine(config) {
320
400
  );
321
401
  }
322
402
  function linkOrderInternal(signer, activityLogId, orderId) {
323
- return ResultAsync.fromPromise(
403
+ return ResultAsync2.fromPromise(
324
404
  (async () => {
325
405
  logger.info("Linking order to activity log", { activityLogId, orderId });
326
406
  const signedHeaders = await getSignedHeaders(signer, "link-order");
@@ -438,7 +518,7 @@ function createFraudEngine(config) {
438
518
  },
439
519
  checkBuyOrder(params) {
440
520
  if (configError) return errAsync(configError);
441
- return ResultAsync.fromPromise(
521
+ return ResultAsync2.fromPromise(
442
522
  checkBuyOrderInternal(params).then((data) => ({
443
523
  approved: data.approved,
444
524
  activityLogId: data.activity_log_id,
@@ -456,7 +536,7 @@ function createFraudEngine(config) {
456
536
  },
457
537
  processBuyOrder(params) {
458
538
  if (configError) return errAsync(configError);
459
- return ResultAsync.fromPromise(
539
+ return ResultAsync2.fromPromise(
460
540
  (async () => {
461
541
  let activityLogId = null;
462
542
  try {
@@ -501,7 +581,7 @@ function createFraudEngine(config) {
501
581
  },
502
582
  logFingerprint(params) {
503
583
  if (configError) return errAsync(configError);
504
- return ResultAsync.fromPromise(
584
+ return ResultAsync2.fromPromise(
505
585
  (async () => {
506
586
  logger.info("Logging fingerprint");
507
587
  const fingerprintResult = await getFingerprint(5e3);
@@ -560,8 +640,12 @@ function createFraudEngine(config) {
560
640
  };
561
641
  }
562
642
 
563
- // src/order-routing/client.ts
564
- import { stringToHex as stringToHex3 } from "viem";
643
+ // src/orders/client.ts
644
+ import { errAsync as errAsync4, okAsync as okAsync4 } from "neverthrow";
645
+
646
+ // src/contracts/order-processor/index.ts
647
+ import { ResultAsync as ResultAsync3 } from "neverthrow";
648
+ import { stringToHex } from "viem";
565
649
 
566
650
  // src/contracts/abis/index.ts
567
651
  import { erc20Abi } from "viem";
@@ -596,64 +680,439 @@ var orderFlowFacetAbi = [
596
680
  ],
597
681
  stateMutability: "view",
598
682
  type: "function"
599
- }
600
- ];
601
-
602
- // src/contracts/abis/p2p-config-facet.ts
603
- var p2pConfigFacetAbi = [
683
+ },
604
684
  {
605
685
  inputs: [
606
- {
607
- internalType: "bytes32",
608
- name: "_currency",
609
- type: "bytes32"
610
- }
686
+ { internalType: "string", name: "_pubKey", type: "string" },
687
+ { internalType: "uint256", name: "_amount", type: "uint256" },
688
+ { internalType: "address", name: "_recipientAddr", type: "address" },
689
+ { internalType: "uint8", name: "_orderType", type: "uint8" },
690
+ { internalType: "string", name: "_userUpi", type: "string" },
691
+ { internalType: "string", name: "_userPubKey", type: "string" },
692
+ { internalType: "bytes32", name: "_currency", type: "bytes32" },
693
+ { internalType: "uint256", name: "preferredPaymentChannelConfigId", type: "uint256" },
694
+ { internalType: "uint256", name: "_circleId", type: "uint256" },
695
+ { internalType: "uint256", name: "_fiatAmountLimit", type: "uint256" }
611
696
  ],
612
- name: "getPriceConfig",
613
- outputs: [
697
+ name: "placeOrder",
698
+ outputs: [],
699
+ stateMutability: "nonpayable",
700
+ type: "function"
701
+ },
702
+ {
703
+ inputs: [{ internalType: "uint256", name: "_orderId", type: "uint256" }],
704
+ name: "cancelOrder",
705
+ outputs: [],
706
+ stateMutability: "nonpayable",
707
+ type: "function"
708
+ },
709
+ {
710
+ inputs: [
711
+ { internalType: "uint256", name: "_orderId", type: "uint256" },
712
+ { internalType: "string", name: "_userEncUpi", type: "string" },
713
+ { internalType: "uint256", name: "_updatedAmount", type: "uint256" }
714
+ ],
715
+ name: "setSellOrderUpi",
716
+ outputs: [],
717
+ stateMutability: "nonpayable",
718
+ type: "function"
719
+ },
720
+ {
721
+ type: "event",
722
+ name: "OrderPlaced",
723
+ anonymous: false,
724
+ inputs: [
725
+ { indexed: true, name: "orderId", type: "uint256" },
726
+ { indexed: true, name: "user", type: "address" },
727
+ { indexed: true, name: "merchant", type: "address" },
728
+ { indexed: false, name: "amount", type: "uint256" },
729
+ { indexed: false, name: "orderType", type: "uint8" },
730
+ { indexed: false, name: "placedTimestamp", type: "uint256" },
614
731
  {
732
+ indexed: false,
733
+ name: "_order",
734
+ type: "tuple",
615
735
  components: [
736
+ { name: "amount", type: "uint256" },
737
+ { name: "fiatAmount", type: "uint256" },
738
+ { name: "placedTimestamp", type: "uint256" },
739
+ { name: "completedTimestamp", type: "uint256" },
740
+ { name: "userCompletedTimestamp", type: "uint256" },
741
+ { name: "acceptedMerchant", type: "address" },
742
+ { name: "user", type: "address" },
743
+ { name: "recipientAddr", type: "address" },
744
+ { name: "pubkey", type: "string" },
745
+ { name: "encUpi", type: "string" },
746
+ { name: "userCompleted", type: "bool" },
747
+ { name: "status", type: "uint8" },
748
+ { name: "orderType", type: "uint8" },
616
749
  {
617
- internalType: "uint256",
618
- name: "buyPrice",
619
- type: "uint256"
750
+ name: "disputeInfo",
751
+ type: "tuple",
752
+ components: [
753
+ { name: "raisedBy", type: "uint8" },
754
+ { name: "status", type: "uint8" },
755
+ { name: "redactTransId", type: "uint256" },
756
+ { name: "accountNumber", type: "uint256" }
757
+ ]
620
758
  },
759
+ { name: "id", type: "uint256" },
760
+ { name: "userPubKey", type: "string" },
761
+ { name: "encMerchantUpi", type: "string" },
762
+ { name: "acceptedAccountNo", type: "uint256" },
763
+ { name: "assignedAccountNos", type: "uint256[]" },
764
+ { name: "currency", type: "bytes32" },
765
+ { name: "preferredPaymentChannelConfigId", type: "uint256" },
766
+ { name: "circleId", type: "uint256" }
767
+ ]
768
+ }
769
+ ]
770
+ },
771
+ {
772
+ type: "event",
773
+ name: "OrderAccepted",
774
+ anonymous: false,
775
+ inputs: [
776
+ { indexed: true, name: "orderId", type: "uint256" },
777
+ { indexed: true, name: "merchant", type: "address" },
778
+ { indexed: false, name: "pubKey", type: "string" },
779
+ {
780
+ indexed: false,
781
+ name: "_order",
782
+ type: "tuple",
783
+ components: [
784
+ { name: "amount", type: "uint256" },
785
+ { name: "fiatAmount", type: "uint256" },
786
+ { name: "placedTimestamp", type: "uint256" },
787
+ { name: "completedTimestamp", type: "uint256" },
788
+ { name: "userCompletedTimestamp", type: "uint256" },
789
+ { name: "acceptedMerchant", type: "address" },
790
+ { name: "user", type: "address" },
791
+ { name: "recipientAddr", type: "address" },
792
+ { name: "pubkey", type: "string" },
793
+ { name: "encUpi", type: "string" },
794
+ { name: "userCompleted", type: "bool" },
795
+ { name: "status", type: "uint8" },
796
+ { name: "orderType", type: "uint8" },
621
797
  {
622
- internalType: "uint256",
623
- name: "sellPrice",
624
- type: "uint256"
798
+ name: "disputeInfo",
799
+ type: "tuple",
800
+ components: [
801
+ { name: "raisedBy", type: "uint8" },
802
+ { name: "status", type: "uint8" },
803
+ { name: "redactTransId", type: "uint256" },
804
+ { name: "accountNumber", type: "uint256" }
805
+ ]
625
806
  },
807
+ { name: "id", type: "uint256" },
808
+ { name: "userPubKey", type: "string" },
809
+ { name: "encMerchantUpi", type: "string" },
810
+ { name: "acceptedAccountNo", type: "uint256" },
811
+ { name: "assignedAccountNos", type: "uint256[]" },
812
+ { name: "currency", type: "bytes32" },
813
+ { name: "preferredPaymentChannelConfigId", type: "uint256" },
814
+ { name: "circleId", type: "uint256" }
815
+ ]
816
+ }
817
+ ]
818
+ },
819
+ {
820
+ type: "event",
821
+ name: "BuyOrderPaid",
822
+ anonymous: false,
823
+ inputs: [
824
+ { indexed: true, name: "orderId", type: "uint256" },
825
+ { indexed: true, name: "user", type: "address" },
826
+ {
827
+ indexed: false,
828
+ name: "_order",
829
+ type: "tuple",
830
+ components: [
831
+ { name: "amount", type: "uint256" },
832
+ { name: "fiatAmount", type: "uint256" },
833
+ { name: "placedTimestamp", type: "uint256" },
834
+ { name: "completedTimestamp", type: "uint256" },
835
+ { name: "userCompletedTimestamp", type: "uint256" },
836
+ { name: "acceptedMerchant", type: "address" },
837
+ { name: "user", type: "address" },
838
+ { name: "recipientAddr", type: "address" },
839
+ { name: "pubkey", type: "string" },
840
+ { name: "encUpi", type: "string" },
841
+ { name: "userCompleted", type: "bool" },
842
+ { name: "status", type: "uint8" },
843
+ { name: "orderType", type: "uint8" },
626
844
  {
627
- internalType: "int256",
628
- name: "buyPriceOffset",
629
- type: "int256"
845
+ name: "disputeInfo",
846
+ type: "tuple",
847
+ components: [
848
+ { name: "raisedBy", type: "uint8" },
849
+ { name: "status", type: "uint8" },
850
+ { name: "redactTransId", type: "uint256" },
851
+ { name: "accountNumber", type: "uint256" }
852
+ ]
630
853
  },
854
+ { name: "id", type: "uint256" },
855
+ { name: "userPubKey", type: "string" },
856
+ { name: "encMerchantUpi", type: "string" },
857
+ { name: "acceptedAccountNo", type: "uint256" },
858
+ { name: "assignedAccountNos", type: "uint256[]" },
859
+ { name: "currency", type: "bytes32" },
860
+ { name: "preferredPaymentChannelConfigId", type: "uint256" },
861
+ { name: "circleId", type: "uint256" }
862
+ ]
863
+ }
864
+ ]
865
+ },
866
+ {
867
+ type: "event",
868
+ name: "OrderCompleted",
869
+ anonymous: false,
870
+ inputs: [
871
+ { indexed: true, name: "orderId", type: "uint256" },
872
+ { indexed: true, name: "user", type: "address" },
873
+ { indexed: false, name: "completedTimestamp", type: "uint256" },
874
+ {
875
+ indexed: false,
876
+ name: "_order",
877
+ type: "tuple",
878
+ components: [
879
+ { name: "amount", type: "uint256" },
880
+ { name: "fiatAmount", type: "uint256" },
881
+ { name: "placedTimestamp", type: "uint256" },
882
+ { name: "completedTimestamp", type: "uint256" },
883
+ { name: "userCompletedTimestamp", type: "uint256" },
884
+ { name: "acceptedMerchant", type: "address" },
885
+ { name: "user", type: "address" },
886
+ { name: "recipientAddr", type: "address" },
887
+ { name: "pubkey", type: "string" },
888
+ { name: "encUpi", type: "string" },
889
+ { name: "userCompleted", type: "bool" },
890
+ { name: "status", type: "uint8" },
891
+ { name: "orderType", type: "uint8" },
631
892
  {
632
- internalType: "uint256",
633
- name: "baseSpread",
634
- type: "uint256"
635
- }
636
- ],
637
- internalType: "struct P2pConfigStorage.PriceConfig",
638
- name: "",
639
- type: "tuple"
893
+ name: "disputeInfo",
894
+ type: "tuple",
895
+ components: [
896
+ { name: "raisedBy", type: "uint8" },
897
+ { name: "status", type: "uint8" },
898
+ { name: "redactTransId", type: "uint256" },
899
+ { name: "accountNumber", type: "uint256" }
900
+ ]
901
+ },
902
+ { name: "id", type: "uint256" },
903
+ { name: "userPubKey", type: "string" },
904
+ { name: "encMerchantUpi", type: "string" },
905
+ { name: "acceptedAccountNo", type: "uint256" },
906
+ { name: "assignedAccountNos", type: "uint256[]" },
907
+ { name: "currency", type: "bytes32" },
908
+ { name: "preferredPaymentChannelConfigId", type: "uint256" },
909
+ { name: "circleId", type: "uint256" }
910
+ ]
640
911
  }
641
- ],
642
- stateMutability: "view",
643
- type: "function"
912
+ ]
644
913
  },
645
914
  {
915
+ type: "event",
916
+ name: "CancelledOrders",
917
+ anonymous: false,
646
918
  inputs: [
919
+ { indexed: true, name: "orderId", type: "uint256" },
647
920
  {
648
- internalType: "bytes32",
649
- name: "_nativeCurrency",
650
- type: "bytes32"
921
+ indexed: false,
922
+ name: "_order",
923
+ type: "tuple",
924
+ components: [
925
+ { name: "amount", type: "uint256" },
926
+ { name: "fiatAmount", type: "uint256" },
927
+ { name: "placedTimestamp", type: "uint256" },
928
+ { name: "completedTimestamp", type: "uint256" },
929
+ { name: "userCompletedTimestamp", type: "uint256" },
930
+ { name: "acceptedMerchant", type: "address" },
931
+ { name: "user", type: "address" },
932
+ { name: "recipientAddr", type: "address" },
933
+ { name: "pubkey", type: "string" },
934
+ { name: "encUpi", type: "string" },
935
+ { name: "userCompleted", type: "bool" },
936
+ { name: "status", type: "uint8" },
937
+ { name: "orderType", type: "uint8" },
938
+ {
939
+ name: "disputeInfo",
940
+ type: "tuple",
941
+ components: [
942
+ { name: "raisedBy", type: "uint8" },
943
+ { name: "status", type: "uint8" },
944
+ { name: "redactTransId", type: "uint256" },
945
+ { name: "accountNumber", type: "uint256" }
946
+ ]
947
+ },
948
+ { name: "id", type: "uint256" },
949
+ { name: "userPubKey", type: "string" },
950
+ { name: "encMerchantUpi", type: "string" },
951
+ { name: "acceptedAccountNo", type: "uint256" },
952
+ { name: "assignedAccountNos", type: "uint256[]" },
953
+ { name: "currency", type: "bytes32" },
954
+ { name: "preferredPaymentChannelConfigId", type: "uint256" },
955
+ { name: "circleId", type: "uint256" }
956
+ ]
651
957
  }
652
- ],
653
- name: "getRpPerUsdtLimitRational",
958
+ ]
959
+ }
960
+ ];
961
+
962
+ // src/contracts/abis/order-processor-facet.ts
963
+ var orderProcessorFacetAbi = [
964
+ {
965
+ type: "function",
966
+ name: "getOrdersById",
967
+ stateMutability: "view",
968
+ inputs: [{ name: "orderId", type: "uint256" }],
654
969
  outputs: [
655
970
  {
656
- internalType: "uint256",
971
+ type: "tuple",
972
+ components: [
973
+ { name: "amount", type: "uint256" },
974
+ { name: "fiatAmount", type: "uint256" },
975
+ { name: "placedTimestamp", type: "uint256" },
976
+ { name: "completedTimestamp", type: "uint256" },
977
+ { name: "userCompletedTimestamp", type: "uint256" },
978
+ { name: "acceptedMerchant", type: "address" },
979
+ { name: "user", type: "address" },
980
+ { name: "recipientAddr", type: "address" },
981
+ { name: "pubkey", type: "string" },
982
+ { name: "encUpi", type: "string" },
983
+ { name: "userCompleted", type: "bool" },
984
+ { name: "status", type: "uint8" },
985
+ { name: "orderType", type: "uint8" },
986
+ {
987
+ name: "disputeInfo",
988
+ type: "tuple",
989
+ components: [
990
+ { name: "raisedBy", type: "uint8" },
991
+ { name: "status", type: "uint8" },
992
+ { name: "redactTransId", type: "uint256" },
993
+ { name: "accountNumber", type: "uint256" }
994
+ ]
995
+ },
996
+ { name: "id", type: "uint256" },
997
+ { name: "userPubKey", type: "string" },
998
+ { name: "encMerchantUpi", type: "string" },
999
+ { name: "acceptedAccountNo", type: "uint256" },
1000
+ { name: "assignedAccountNos", type: "uint256[]" },
1001
+ { name: "currency", type: "bytes32" },
1002
+ { name: "preferredPaymentChannelConfigId", type: "uint256" },
1003
+ { name: "circleId", type: "uint256" }
1004
+ ]
1005
+ }
1006
+ ]
1007
+ },
1008
+ {
1009
+ type: "function",
1010
+ name: "getAdditionalOrderDetails",
1011
+ stateMutability: "view",
1012
+ inputs: [{ name: "orderId", type: "uint256" }],
1013
+ outputs: [
1014
+ {
1015
+ type: "tuple",
1016
+ components: [
1017
+ { name: "fixedFeePaid", type: "uint64" },
1018
+ { name: "tipsPaid", type: "uint64" },
1019
+ { name: "acceptedTimestamp", type: "uint128" },
1020
+ { name: "paidTimestamp", type: "uint128" },
1021
+ { name: "reserved2", type: "uint128" },
1022
+ { name: "actualUsdtAmount", type: "uint256" },
1023
+ { name: "actualFiatAmount", type: "uint256" }
1024
+ ]
1025
+ }
1026
+ ]
1027
+ },
1028
+ {
1029
+ type: "function",
1030
+ name: "getSmallOrderThreshold",
1031
+ stateMutability: "view",
1032
+ inputs: [{ name: "currency", type: "bytes32" }],
1033
+ outputs: [{ name: "", type: "uint256" }]
1034
+ },
1035
+ {
1036
+ type: "function",
1037
+ name: "getSmallOrderFixedFee",
1038
+ stateMutability: "view",
1039
+ inputs: [{ name: "currency", type: "bytes32" }],
1040
+ outputs: [{ name: "", type: "uint256" }]
1041
+ },
1042
+ {
1043
+ type: "function",
1044
+ name: "raiseDispute",
1045
+ stateMutability: "nonpayable",
1046
+ inputs: [
1047
+ { name: "_orderId", type: "uint256" },
1048
+ { name: "redactTransId", type: "uint256" }
1049
+ ],
1050
+ outputs: []
1051
+ },
1052
+ {
1053
+ type: "function",
1054
+ name: "paidBuyOrder",
1055
+ stateMutability: "nonpayable",
1056
+ inputs: [{ name: "_orderId", type: "uint256" }],
1057
+ outputs: []
1058
+ }
1059
+ ];
1060
+
1061
+ // src/contracts/abis/p2p-config-facet.ts
1062
+ var p2pConfigFacetAbi = [
1063
+ {
1064
+ inputs: [
1065
+ {
1066
+ internalType: "bytes32",
1067
+ name: "_currency",
1068
+ type: "bytes32"
1069
+ }
1070
+ ],
1071
+ name: "getPriceConfig",
1072
+ outputs: [
1073
+ {
1074
+ components: [
1075
+ {
1076
+ internalType: "uint256",
1077
+ name: "buyPrice",
1078
+ type: "uint256"
1079
+ },
1080
+ {
1081
+ internalType: "uint256",
1082
+ name: "sellPrice",
1083
+ type: "uint256"
1084
+ },
1085
+ {
1086
+ internalType: "int256",
1087
+ name: "buyPriceOffset",
1088
+ type: "int256"
1089
+ },
1090
+ {
1091
+ internalType: "uint256",
1092
+ name: "baseSpread",
1093
+ type: "uint256"
1094
+ }
1095
+ ],
1096
+ internalType: "struct P2pConfigStorage.PriceConfig",
1097
+ name: "",
1098
+ type: "tuple"
1099
+ }
1100
+ ],
1101
+ stateMutability: "view",
1102
+ type: "function"
1103
+ },
1104
+ {
1105
+ inputs: [
1106
+ {
1107
+ internalType: "bytes32",
1108
+ name: "_nativeCurrency",
1109
+ type: "bytes32"
1110
+ }
1111
+ ],
1112
+ name: "getRpPerUsdtLimitRational",
1113
+ outputs: [
1114
+ {
1115
+ internalType: "uint256",
657
1116
  name: "numerator",
658
1117
  type: "uint256"
659
1118
  },
@@ -871,11 +1330,16 @@ var reputationManagerAbi = [
871
1330
  ];
872
1331
 
873
1332
  // src/contracts/abis/index.ts
874
- var DIAMOND_ABI = [...orderFlowFacetAbi, ...p2pConfigFacetAbi];
1333
+ var DIAMOND_ABI = [
1334
+ ...orderFlowFacetAbi,
1335
+ ...orderProcessorFacetAbi,
1336
+ ...p2pConfigFacetAbi
1337
+ ];
875
1338
  var ABIS = {
876
1339
  DIAMOND: DIAMOND_ABI,
877
1340
  FACETS: {
878
1341
  ORDER_FLOW: orderFlowFacetAbi,
1342
+ ORDER_PROCESSOR: orderProcessorFacetAbi,
879
1343
  CONFIG: p2pConfigFacetAbi
880
1344
  },
881
1345
  EXTERNAL: {
@@ -884,718 +1348,564 @@ var ABIS = {
884
1348
  }
885
1349
  };
886
1350
 
887
- // src/contracts/order-flow/index.ts
888
- import { ResultAsync as ResultAsync2 } from "neverthrow";
1351
+ // src/contracts/order-processor/index.ts
1352
+ function readOrderMulticall(publicClient, diamondAddress, orderId) {
1353
+ const calls = [
1354
+ {
1355
+ address: diamondAddress,
1356
+ abi: ABIS.FACETS.ORDER_PROCESSOR,
1357
+ functionName: "getOrdersById",
1358
+ args: [orderId]
1359
+ },
1360
+ {
1361
+ address: diamondAddress,
1362
+ abi: ABIS.FACETS.ORDER_PROCESSOR,
1363
+ functionName: "getAdditionalOrderDetails",
1364
+ args: [orderId]
1365
+ }
1366
+ ];
1367
+ const toError = (error) => new Error("Order contract read failed", { cause: error });
1368
+ const exec = async () => {
1369
+ if (publicClient.multicall) {
1370
+ const [order2, details2] = await publicClient.multicall({
1371
+ contracts: calls,
1372
+ allowFailure: false
1373
+ });
1374
+ return { order: order2, details: details2 };
1375
+ }
1376
+ const [order, details] = await Promise.all(
1377
+ calls.map((c) => publicClient.readContract(c))
1378
+ );
1379
+ return { order, details };
1380
+ };
1381
+ return ResultAsync3.fromPromise(exec(), toError);
1382
+ }
1383
+ function readFeeConfigMulticall(publicClient, diamondAddress, currency) {
1384
+ const currencyHex = stringToHex(currency, { size: 32 });
1385
+ const calls = [
1386
+ {
1387
+ address: diamondAddress,
1388
+ abi: ABIS.FACETS.ORDER_PROCESSOR,
1389
+ functionName: "getSmallOrderThreshold",
1390
+ args: [currencyHex]
1391
+ },
1392
+ {
1393
+ address: diamondAddress,
1394
+ abi: ABIS.FACETS.ORDER_PROCESSOR,
1395
+ functionName: "getSmallOrderFixedFee",
1396
+ args: [currencyHex]
1397
+ }
1398
+ ];
1399
+ const toError = (error) => new Error("Fee config contract read failed", { cause: error });
1400
+ const exec = async () => {
1401
+ if (publicClient.multicall) {
1402
+ const [smallOrderThreshold2, smallOrderFixedFee2] = await publicClient.multicall({
1403
+ contracts: calls,
1404
+ allowFailure: false
1405
+ });
1406
+ return { smallOrderThreshold: smallOrderThreshold2, smallOrderFixedFee: smallOrderFixedFee2 };
1407
+ }
1408
+ const [smallOrderThreshold, smallOrderFixedFee] = await Promise.all(
1409
+ calls.map((c) => publicClient.readContract(c))
1410
+ );
1411
+ return { smallOrderThreshold, smallOrderFixedFee };
1412
+ };
1413
+ return ResultAsync3.fromPromise(exec(), toError);
1414
+ }
889
1415
 
890
- // src/order-routing/errors.ts
891
- var OrderRoutingError = class extends SdkError {
1416
+ // src/orders/actions/approve-usdc.ts
1417
+ import { encodeFunctionData, erc20Abi as erc20Abi2 } from "viem";
1418
+
1419
+ // src/orders/errors.ts
1420
+ var OrdersError = class extends SdkError {
892
1421
  constructor(message, options) {
893
1422
  super(message, options);
894
- this.name = "OrderRoutingError";
1423
+ this.name = "OrdersError";
895
1424
  }
896
1425
  };
897
1426
 
898
- // src/order-routing/validation.ts
1427
+ // src/orders/tx.ts
1428
+ import { errAsync as errAsync2, okAsync, ResultAsync as ResultAsync4 } from "neverthrow";
1429
+ function submitPreparedTx(input) {
1430
+ const { prepared, walletClient, publicClient, waitForReceipt, extraMeta } = input;
1431
+ const account = walletClient.account;
1432
+ if (!account) {
1433
+ return errAsync2(
1434
+ new OrdersError("WalletClient is missing an account", {
1435
+ code: "TX_SUBMISSION_FAILED"
1436
+ })
1437
+ );
1438
+ }
1439
+ const chain = walletClient.chain;
1440
+ return ResultAsync4.fromPromise(
1441
+ walletClient.sendTransaction({
1442
+ account,
1443
+ chain,
1444
+ to: prepared.to,
1445
+ data: prepared.data,
1446
+ value: prepared.value
1447
+ }),
1448
+ (cause) => new OrdersError("walletClient.sendTransaction rejected", {
1449
+ code: "TX_SUBMISSION_FAILED",
1450
+ cause
1451
+ })
1452
+ ).andThen((hash) => {
1453
+ const combinedMeta = prepared.meta || extraMeta ? { ...prepared.meta, ...extraMeta } : void 0;
1454
+ if (!waitForReceipt) {
1455
+ return okAsync({ hash, meta: combinedMeta });
1456
+ }
1457
+ return ResultAsync4.fromPromise(
1458
+ publicClient.waitForTransactionReceipt({ hash }),
1459
+ (cause) => new OrdersError("waitForTransactionReceipt failed", {
1460
+ code: "RECEIPT_TIMEOUT",
1461
+ cause
1462
+ })
1463
+ ).andThen((receipt) => {
1464
+ if (receipt.status !== "success") {
1465
+ return errAsync2(
1466
+ new OrdersError("Transaction reverted", {
1467
+ code: "TX_REVERTED",
1468
+ context: { hash, blockNumber: receipt.blockNumber.toString() }
1469
+ })
1470
+ );
1471
+ }
1472
+ return okAsync({ hash, receipt, meta: combinedMeta });
1473
+ });
1474
+ });
1475
+ }
1476
+
1477
+ // src/orders/validation.ts
899
1478
  import { z as z3 } from "zod";
900
- var ZodCircleScoreStateSchema = z3.object({
901
- activeMerchantsCount: z3.coerce.number()
902
- });
903
- var ZodCircleMetricsForRoutingSchema = z3.object({
904
- circleScore: z3.coerce.number(),
905
- circleStatus: z3.string(),
906
- scoreState: ZodCircleScoreStateSchema
1479
+ var ZodGetOrderParamsSchema = z3.object({
1480
+ orderId: z3.bigint().positive()
907
1481
  });
908
- var ZodCircleForRoutingSchema = z3.object({
909
- circleId: z3.string(),
910
- currency: z3.string(),
911
- metrics: ZodCircleMetricsForRoutingSchema
1482
+ var ZodGetFeeConfigParamsSchema = z3.object({
1483
+ currency: ZodCurrencySchema
912
1484
  });
913
- var ZodCirclesForRoutingResponseSchema = z3.object({
914
- circles: z3.array(ZodCircleForRoutingSchema)
1485
+ var ZodGetOrdersParamsSchema = z3.object({
1486
+ userAddress: ZodAddressSchema,
1487
+ skip: z3.number().int().min(0).default(0),
1488
+ limit: z3.number().int().min(1).max(100).default(20)
915
1489
  });
916
- var ZodCheckCircleEligibilityParamsSchema = z3.object({
917
- circleId: z3.bigint(),
918
- currency: z3.string(),
1490
+ var ZodPlaceOrderParamsSchema = z3.object({
1491
+ orderType: z3.number().int().min(0).max(2),
1492
+ currency: ZodCurrencySchema,
919
1493
  user: ZodAddressSchema,
920
- usdtAmount: z3.bigint(),
1494
+ amount: z3.bigint(),
921
1495
  fiatAmount: z3.bigint(),
922
- orderType: z3.bigint(),
923
- preferredPCConfigId: z3.bigint()
1496
+ fiatAmountLimit: z3.bigint().optional().default(0n),
1497
+ recipientAddr: ZodAddressSchema,
1498
+ preferredPaymentChannelConfigId: z3.bigint().optional(),
1499
+ pubKey: z3.string().optional()
924
1500
  });
925
- var ZodSelectCircleParamsSchema = z3.object({
926
- currency: z3.string().min(1),
927
- user: ZodAddressSchema,
928
- usdtAmount: z3.bigint(),
929
- fiatAmount: z3.bigint(),
930
- orderType: z3.bigint(),
931
- preferredPCConfigId: z3.bigint()
1501
+ var ZodCancelOrderParamsSchema = z3.object({
1502
+ orderId: z3.bigint().nonnegative()
932
1503
  });
933
-
934
- // src/contracts/order-flow/index.ts
935
- function checkCircleEligibility(publicClient, contractAddress, params, logger = noopLogger) {
936
- return validate(
937
- ZodCheckCircleEligibilityParamsSchema,
938
- params,
939
- (message, cause, d) => new OrderRoutingError(message, { code: "VALIDATION_ERROR", cause, context: { data: d } })
940
- ).asyncAndThen((validated) => {
941
- logger.debug("checking on-chain eligibility", {
942
- circleId: String(validated.circleId),
943
- contractAddress
944
- });
945
- return ResultAsync2.fromPromise(
946
- publicClient.readContract({
947
- address: contractAddress,
948
- abi: ABIS.FACETS.ORDER_FLOW,
949
- functionName: "getAssignableMerchantsFromCircle",
950
- args: [
951
- validated.circleId,
952
- 1n,
953
- validated.currency,
954
- validated.user,
955
- validated.usdtAmount,
956
- validated.fiatAmount,
957
- validated.orderType,
958
- validated.preferredPCConfigId
959
- ]
960
- }),
961
- (error) => new OrderRoutingError("Eligibility check failed", {
962
- code: "CONTRACT_READ_ERROR",
963
- cause: error,
964
- context: { circleId: String(params.circleId) }
965
- })
966
- );
967
- }).map((merchants) => {
968
- const arr = merchants;
969
- const eligible = arr.length >= 1;
970
- logger.debug("eligibility check result", {
971
- circleId: String(params.circleId),
972
- assignableMerchants: arr.length,
973
- eligible
974
- });
975
- return eligible;
976
- });
977
- }
978
-
979
- // src/contracts/p2p-config/index.ts
980
- import { ResultAsync as ResultAsync3 } from "neverthrow";
981
- import { stringToHex } from "viem";
982
-
983
- // src/profile/errors.ts
984
- var ProfileError = class extends SdkError {
985
- constructor(message, options) {
986
- super(message, options);
987
- this.name = "ProfileError";
988
- }
989
- };
990
-
991
- // src/profile/validation.ts
992
- import { z as z4 } from "zod";
993
- var ZodUsdcBalanceParamsSchema = z4.object({
994
- address: ZodAddressSchema
1504
+ var ZodSetSellOrderUpiParamsSchema = z3.object({
1505
+ orderId: z3.bigint().nonnegative(),
1506
+ paymentAddress: z3.string().min(1),
1507
+ merchantPublicKey: z3.string().min(1),
1508
+ updatedAmount: z3.bigint()
995
1509
  });
996
- var ZodGetBalancesParamsSchema = z4.object({
997
- address: ZodAddressSchema,
998
- currency: ZodCurrencySchema
1510
+ var ZodRaiseDisputeParamsSchema = z3.object({
1511
+ orderId: z3.bigint().nonnegative(),
1512
+ redactTransId: z3.bigint().nonnegative()
999
1513
  });
1000
- var ZodTxLimitsParamsSchema = z4.object({
1001
- address: ZodAddressSchema,
1002
- currency: ZodCurrencySchema
1514
+ var ZodApproveUsdcParamsSchema = z3.object({
1515
+ amount: z3.bigint().nonnegative()
1003
1516
  });
1004
- var ZodPriceConfigParamsSchema = z4.object({
1005
- currency: ZodCurrencySchema
1517
+ var ZodPaidBuyOrderParamsSchema = z3.object({
1518
+ orderId: z3.bigint().nonnegative()
1519
+ });
1520
+ var HexString = z3.string().regex(/^0x[0-9a-fA-F]*$/, "Expected 0x-prefixed hex");
1521
+ var ZodSubgraphOrderSchema = z3.object({
1522
+ orderId: z3.string(),
1523
+ type: z3.number().int().min(0),
1524
+ status: z3.number().int().min(0),
1525
+ circleId: z3.string(),
1526
+ userAddress: HexString,
1527
+ usdcRecipientAddress: HexString,
1528
+ acceptedMerchantAddress: HexString,
1529
+ usdcAmount: z3.string(),
1530
+ fiatAmount: z3.string(),
1531
+ actualUsdcAmount: z3.string(),
1532
+ actualFiatAmount: z3.string(),
1533
+ currency: HexString,
1534
+ placedAt: z3.string(),
1535
+ acceptedAt: z3.string(),
1536
+ paidAt: z3.string(),
1537
+ completedAt: z3.string(),
1538
+ fixedFeePaid: z3.string(),
1539
+ tipsPaid: z3.string(),
1540
+ disputeStatus: z3.number().int().min(0)
1541
+ });
1542
+ var ZodSubgraphOrdersResponseSchema = z3.object({
1543
+ orders_collection: z3.array(ZodSubgraphOrderSchema)
1006
1544
  });
1007
1545
 
1008
- // src/contracts/p2p-config/index.ts
1009
- function getPriceConfig(publicClient, diamondAddress, params) {
1010
- return validate(
1011
- ZodPriceConfigParamsSchema,
1546
+ // src/orders/actions/approve-usdc.ts
1547
+ function createApproveUsdcAction(input) {
1548
+ const { publicClient, diamondAddress, usdcAddress } = input;
1549
+ const prepareFn = (params) => validate(
1550
+ ZodApproveUsdcParamsSchema,
1012
1551
  params,
1013
- (message, cause, data) => new ProfileError(message, {
1552
+ (message, cause, data) => new OrdersError(message, {
1014
1553
  code: "VALIDATION_ERROR",
1015
1554
  cause,
1016
- context: { params: data }
1555
+ context: { data }
1017
1556
  })
1018
- ).asyncAndThen(
1019
- (validated) => ResultAsync3.fromPromise(
1020
- publicClient.readContract({
1021
- address: diamondAddress,
1022
- abi: ABIS.FACETS.CONFIG,
1023
- functionName: "getPriceConfig",
1024
- args: [stringToHex(validated.currency, { size: 32 })]
1025
- }),
1026
- (error) => new ProfileError("Failed to read price config", {
1027
- code: "CONTRACT_READ_ERROR",
1028
- cause: error,
1029
- context: { currency: validated.currency, diamondAddress }
1030
- })
1031
- )
1032
- );
1557
+ ).map(({ amount }) => ({
1558
+ to: usdcAddress,
1559
+ data: encodeFunctionData({
1560
+ abi: erc20Abi2,
1561
+ functionName: "approve",
1562
+ args: [diamondAddress, amount]
1563
+ }),
1564
+ value: 0n
1565
+ }));
1566
+ return {
1567
+ prepare(params) {
1568
+ return prepareFn(params).asyncMap(async (tx) => tx);
1569
+ },
1570
+ execute({ walletClient, waitForReceipt, ...params }) {
1571
+ return prepareFn(params).asyncAndThen(
1572
+ (prepared) => submitPreparedTx({ prepared, walletClient, publicClient, waitForReceipt })
1573
+ );
1574
+ }
1575
+ };
1033
1576
  }
1034
1577
 
1035
- // src/contracts/reputation-manager/writes.ts
1036
- import { Result } from "neverthrow";
1037
- import { encodeFunctionData } from "viem";
1038
-
1039
- // src/zkkyc/errors.ts
1040
- var ZkkycError = class extends SdkError {
1041
- constructor(message, options) {
1042
- super(message, options);
1043
- this.name = "ZkkycError";
1044
- }
1045
- };
1046
-
1047
- // src/zkkyc/validation.ts
1048
- import { z as z5 } from "zod";
1049
- var ZodAnonAadharProofParamsSchema = z5.object({
1050
- nullifierSeed: z5.bigint(),
1051
- nullifier: z5.bigint(),
1052
- timestamp: z5.bigint(),
1053
- signal: z5.bigint(),
1054
- revealArray: z5.tuple([z5.bigint(), z5.bigint(), z5.bigint(), z5.bigint()]),
1055
- packedGroth16Proof: z5.tuple([
1056
- z5.bigint(),
1057
- z5.bigint(),
1058
- z5.bigint(),
1059
- z5.bigint(),
1060
- z5.bigint(),
1061
- z5.bigint(),
1062
- z5.bigint(),
1063
- z5.bigint()
1064
- ])
1065
- });
1066
- var ZodSocialVerifyParamsSchema = z5.object({
1067
- _socialName: z5.string(),
1068
- proofs: z5.array(
1069
- z5.object({
1070
- claimInfo: z5.object({
1071
- provider: z5.string(),
1072
- parameters: z5.string(),
1073
- context: z5.string()
1074
- }),
1075
- signedClaim: z5.object({
1076
- claim: z5.object({
1077
- identifier: z5.string(),
1078
- owner: ZodAddressSchema,
1079
- timestampS: z5.number(),
1080
- epoch: z5.number()
1081
- }),
1082
- signatures: z5.array(z5.string())
1083
- })
1578
+ // src/orders/actions/cancel-order.ts
1579
+ import { encodeFunctionData as encodeFunctionData2 } from "viem";
1580
+ function createCancelOrderAction(input) {
1581
+ const { publicClient, diamondAddress } = input;
1582
+ const prepareFn = (params) => validate(
1583
+ ZodCancelOrderParamsSchema,
1584
+ params,
1585
+ (message, cause, data) => new OrdersError(message, {
1586
+ code: "VALIDATION_ERROR",
1587
+ cause,
1588
+ context: { data }
1084
1589
  })
1085
- )
1086
- });
1087
- var ZodSolidityVerifierParametersSchema = z5.object({
1088
- version: z5.string().refine((val) => val.startsWith("0x"), {
1089
- message: "Version must be a hex string"
1090
- }),
1091
- proofVerificationData: z5.object({
1092
- vkeyHash: z5.string().refine((val) => /^0x[a-fA-F0-9]{64}$/.test(val), {
1093
- message: "Invalid bytes32 hex string"
1590
+ ).map(({ orderId }) => ({
1591
+ to: diamondAddress,
1592
+ data: encodeFunctionData2({
1593
+ abi: ABIS.FACETS.ORDER_FLOW,
1594
+ functionName: "cancelOrder",
1595
+ args: [orderId]
1094
1596
  }),
1095
- proof: z5.string().refine((val) => val.startsWith("0x"), {
1096
- message: "Proof must be a hex string"
1097
- }),
1098
- publicInputs: z5.array(
1099
- z5.string().refine((val) => /^0x[a-fA-F0-9]{64}$/.test(val), {
1100
- message: "Each public input must be a valid bytes32 hex string"
1101
- })
1102
- )
1103
- }),
1104
- committedInputs: z5.string().refine((val) => val.startsWith("0x"), {
1105
- message: "Committed inputs must be a hex string"
1106
- }),
1107
- serviceConfig: z5.object({
1108
- validityPeriodInSeconds: z5.number().int().nonnegative(),
1109
- domain: z5.string(),
1110
- scope: z5.string(),
1111
- devMode: z5.boolean()
1112
- })
1113
- });
1114
- var ZodZkPassportRegisterParamsSchema = z5.object({
1115
- params: ZodSolidityVerifierParametersSchema,
1116
- isIDCard: z5.boolean()
1117
- });
1597
+ value: 0n
1598
+ }));
1599
+ return {
1600
+ prepare(params) {
1601
+ return prepareFn(params).asyncMap(async (tx) => tx);
1602
+ },
1603
+ execute({ walletClient, waitForReceipt, ...params }) {
1604
+ return prepareFn(params).asyncAndThen(
1605
+ (prepared) => submitPreparedTx({ prepared, walletClient, publicClient, waitForReceipt })
1606
+ );
1607
+ }
1608
+ };
1609
+ }
1118
1610
 
1119
- // src/contracts/reputation-manager/writes.ts
1120
- function prepareSocialVerify(reputationManagerAddress, params) {
1121
- return validate(
1122
- ZodSocialVerifyParamsSchema,
1611
+ // src/orders/actions/paid-buy-order.ts
1612
+ import { encodeFunctionData as encodeFunctionData3 } from "viem";
1613
+ function createPaidBuyOrderAction(input) {
1614
+ const { publicClient, diamondAddress } = input;
1615
+ const prepareFn = (params) => validate(
1616
+ ZodPaidBuyOrderParamsSchema,
1123
1617
  params,
1124
- (message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
1125
- ).andThen(
1126
- (validated) => Result.fromThrowable(
1127
- () => ({
1128
- to: reputationManagerAddress,
1129
- data: encodeFunctionData({
1130
- abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
1131
- functionName: "socialVerify",
1132
- args: [
1133
- validated._socialName,
1134
- validated.proofs.map((proof) => ({
1135
- ...proof,
1136
- signedClaim: {
1137
- ...proof.signedClaim,
1138
- claim: {
1139
- ...proof.signedClaim.claim,
1140
- identifier: proof.signedClaim.claim.identifier
1141
- },
1142
- signatures: proof.signedClaim.signatures
1143
- }
1144
- }))
1145
- ]
1618
+ (message, cause, data) => new OrdersError(message, {
1619
+ code: "VALIDATION_ERROR",
1620
+ cause,
1621
+ context: { data }
1622
+ })
1623
+ ).map(({ orderId }) => ({
1624
+ to: diamondAddress,
1625
+ data: encodeFunctionData3({
1626
+ abi: ABIS.FACETS.ORDER_PROCESSOR,
1627
+ functionName: "paidBuyOrder",
1628
+ args: [orderId]
1629
+ }),
1630
+ value: 0n
1631
+ }));
1632
+ return {
1633
+ prepare(params) {
1634
+ return prepareFn(params).asyncMap(async (tx) => tx);
1635
+ },
1636
+ execute({ walletClient, waitForReceipt, ...params }) {
1637
+ return prepareFn(params).asyncAndThen(
1638
+ (prepared) => submitPreparedTx({ prepared, walletClient, publicClient, waitForReceipt })
1639
+ );
1640
+ }
1641
+ };
1642
+ }
1643
+
1644
+ // src/orders/actions/place-order.ts
1645
+ import { encodeFunctionData as encodeFunctionData4, parseEventLogs, stringToHex as stringToHex2 } from "viem";
1646
+
1647
+ // src/constants/orders.constant.ts
1648
+ var ORDER_TYPE = {
1649
+ BUY: 0,
1650
+ SELL: 1,
1651
+ PAY: 2
1652
+ };
1653
+ var ORDER_STATUS = {
1654
+ PLACED: 0,
1655
+ ACCEPTED: 1,
1656
+ PAID: 2,
1657
+ COMPLETED: 3,
1658
+ CANCELLED: 4
1659
+ };
1660
+ var DISPUTE_STATUS = {
1661
+ NONE: 0,
1662
+ OPEN: 1,
1663
+ RESOLVED: 2
1664
+ };
1665
+
1666
+ // src/orders/relay-identity/identity.ts
1667
+ import { isAddress as isAddress2, isHex } from "viem";
1668
+ import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
1669
+ import { z as z4 } from "zod";
1670
+ var ZodRelayIdentitySchema = z4.object({
1671
+ address: z4.string().refine(isAddress2, { message: "Invalid relay identity address" }),
1672
+ publicKey: z4.string().refine((v) => isHex(`0x${v}`), {
1673
+ message: "Invalid relay identity public key"
1674
+ }),
1675
+ privateKey: z4.string().refine(isHex, { message: "Invalid relay identity private key" })
1676
+ });
1677
+ function createRelayIdentity() {
1678
+ const privateKey = generatePrivateKey();
1679
+ const account = privateKeyToAccount(privateKey);
1680
+ const publicKey = account.publicKey.slice(4);
1681
+ return {
1682
+ address: account.address,
1683
+ publicKey,
1684
+ privateKey
1685
+ };
1686
+ }
1687
+
1688
+ // src/orders/relay-identity/resolve.ts
1689
+ import { err as err3, ok as ok3, okAsync as okAsync2, ResultAsync as ResultAsync5 } from "neverthrow";
1690
+
1691
+ // src/orders/relay-identity/stores.ts
1692
+ var RelayIdentityCorruptError = class extends Error {
1693
+ constructor(cause) {
1694
+ super("Stored relay identity is corrupt", { cause });
1695
+ this.name = "RelayIdentityCorruptError";
1696
+ }
1697
+ };
1698
+ function createInMemoryRelayStore() {
1699
+ let value = null;
1700
+ return {
1701
+ async get() {
1702
+ return value;
1703
+ },
1704
+ async set(identity) {
1705
+ value = identity;
1706
+ }
1707
+ };
1708
+ }
1709
+
1710
+ // src/orders/relay-identity/resolve.ts
1711
+ var pending = /* @__PURE__ */ new WeakMap();
1712
+ async function resolveFromStore(store) {
1713
+ let stored;
1714
+ try {
1715
+ stored = await store.get();
1716
+ } catch (cause) {
1717
+ if (cause instanceof RelayIdentityCorruptError) {
1718
+ return err3(
1719
+ new OrdersError("Stored relay identity is corrupt", {
1720
+ code: "RELAY_IDENTITY_CORRUPT",
1721
+ cause: cause.cause
1146
1722
  })
1147
- }),
1148
- (error) => new ZkkycError("Failed to encode socialVerify", {
1149
- code: "ENCODE_ERROR",
1150
- cause: error
1723
+ );
1724
+ }
1725
+ return err3(
1726
+ new OrdersError("Relay identity store.get failed", {
1727
+ code: "RELAY_IDENTITY_STORE_FAILED",
1728
+ cause
1151
1729
  })
1152
- )()
1153
- );
1154
- }
1155
- function prepareSubmitAnonAadharProof(reputationManagerAddress, params) {
1156
- return validate(
1157
- ZodAnonAadharProofParamsSchema,
1158
- params,
1159
- (message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
1160
- ).andThen(
1161
- (validated) => Result.fromThrowable(
1162
- () => ({
1163
- to: reputationManagerAddress,
1164
- data: encodeFunctionData({
1165
- abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
1166
- functionName: "submitAnonAadharProof",
1167
- args: [
1168
- validated.nullifierSeed,
1169
- validated.nullifier,
1170
- validated.timestamp,
1171
- validated.signal,
1172
- validated.revealArray,
1173
- validated.packedGroth16Proof
1174
- ]
1730
+ );
1731
+ }
1732
+ if (stored !== null) {
1733
+ const parsed = ZodRelayIdentitySchema.safeParse(stored);
1734
+ if (!parsed.success) {
1735
+ return err3(
1736
+ new OrdersError("Stored relay identity failed validation", {
1737
+ code: "RELAY_IDENTITY_CORRUPT",
1738
+ cause: parsed.error
1175
1739
  })
1176
- }),
1177
- (error) => new ZkkycError("Failed to encode submitAnonAadharProof", {
1178
- code: "ENCODE_ERROR",
1179
- cause: error
1740
+ );
1741
+ }
1742
+ return ok3(stored);
1743
+ }
1744
+ const fresh = createRelayIdentity();
1745
+ try {
1746
+ await store.set(fresh);
1747
+ } catch (cause) {
1748
+ return err3(
1749
+ new OrdersError("Relay identity store.set failed", {
1750
+ code: "RELAY_IDENTITY_STORE_FAILED",
1751
+ cause
1180
1752
  })
1181
- )()
1182
- );
1753
+ );
1754
+ }
1755
+ return ok3(fresh);
1183
1756
  }
1184
- function prepareZkPassportRegister(reputationManagerAddress, params) {
1185
- return validate(
1186
- ZodZkPassportRegisterParamsSchema,
1187
- params,
1188
- (message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
1189
- ).andThen(
1190
- (validated) => Result.fromThrowable(
1191
- () => {
1192
- const { proofVerificationData, serviceConfig, committedInputs, version } = validated.params;
1193
- const proofVerificationParams = {
1194
- version,
1195
- proofVerificationData: {
1196
- vkeyHash: proofVerificationData.vkeyHash,
1197
- proof: proofVerificationData.proof,
1198
- publicInputs: proofVerificationData.publicInputs
1199
- },
1200
- committedInputs,
1201
- serviceConfig: {
1202
- validityPeriodInSeconds: BigInt(serviceConfig.validityPeriodInSeconds),
1203
- domain: serviceConfig.domain,
1204
- scope: serviceConfig.scope,
1205
- devMode: serviceConfig.devMode
1206
- }
1207
- };
1208
- return {
1209
- to: reputationManagerAddress,
1210
- data: encodeFunctionData({
1211
- abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
1212
- functionName: "zkPassportRegister",
1213
- args: [proofVerificationParams, validated.isIDCard]
1214
- })
1215
- };
1216
- },
1217
- (error) => new ZkkycError("Failed to encode zkPassportRegister", {
1218
- code: "ENCODE_ERROR",
1219
- cause: error
1220
- })
1221
- )()
1222
- );
1757
+ function resolveRelayIdentity(input) {
1758
+ if (input.relayIdentity) {
1759
+ return okAsync2(input.relayIdentity);
1760
+ }
1761
+ const existing = pending.get(input.store);
1762
+ if (existing) {
1763
+ return ResultAsync5.fromSafePromise(existing).andThen((r) => r);
1764
+ }
1765
+ const promise = resolveFromStore(input.store).finally(() => {
1766
+ pending.delete(input.store);
1767
+ });
1768
+ pending.set(input.store, promise);
1769
+ return ResultAsync5.fromSafePromise(promise).andThen((r) => r);
1223
1770
  }
1224
1771
 
1225
- // src/contracts/tx-limits/index.ts
1226
- import { ResultAsync as ResultAsync4 } from "neverthrow";
1227
- import { formatUnits, stringToHex as stringToHex2 } from "viem";
1228
- function getTxLimits(publicClient, diamondAddress, params) {
1229
- return validate(
1230
- ZodTxLimitsParamsSchema,
1231
- params,
1232
- (message, cause, data) => new ProfileError(message, {
1233
- code: "VALIDATION_ERROR",
1234
- cause,
1235
- context: { params: data }
1236
- })
1237
- ).asyncAndThen(
1238
- (validated) => ResultAsync4.fromPromise(
1239
- publicClient.readContract({
1240
- address: diamondAddress,
1241
- abi: ABIS.FACETS.ORDER_FLOW,
1242
- functionName: "userTxLimit",
1243
- args: [validated.address, stringToHex2(validated.currency, { size: 32 })]
1244
- }),
1245
- (error) => new ProfileError("Failed to read tx limits", {
1246
- code: "CONTRACT_READ_ERROR",
1247
- cause: error,
1248
- context: { address: validated.address, currency: validated.currency, diamondAddress }
1249
- })
1250
- ).map(([buyLimit, sellLimit]) => ({
1251
- buyLimit: Number(formatUnits(buyLimit, 6)),
1252
- sellLimit: Number(formatUnits(sellLimit, 6))
1253
- }))
1254
- );
1772
+ // src/orders/actions/place-order.ts
1773
+ function enrichWithOrderId(result, userAddress) {
1774
+ if (!result.receipt) return result;
1775
+ try {
1776
+ const events = parseEventLogs({
1777
+ abi: ABIS.FACETS.ORDER_FLOW,
1778
+ eventName: "OrderPlaced",
1779
+ logs: result.receipt.logs
1780
+ });
1781
+ const lowered = userAddress.toLowerCase();
1782
+ const mine = events.find((e) => e.args.user?.toLowerCase() === lowered);
1783
+ const chosen = mine ?? events[0];
1784
+ if (!chosen) return result;
1785
+ const orderId = chosen.args.orderId;
1786
+ if (orderId === void 0) return result;
1787
+ return { ...result, meta: { ...result.meta, orderId } };
1788
+ } catch {
1789
+ return result;
1790
+ }
1255
1791
  }
1256
- function getRpPerUsdtLimitRational(publicClient, diamondAddress, params) {
1257
- return validate(
1258
- ZodPriceConfigParamsSchema,
1792
+ function createPlaceOrderAction(input) {
1793
+ const { publicClient, diamondAddress, orderRouter, relayIdentityStore, relayIdentity } = input;
1794
+ const prepareFn = (params) => validate(
1795
+ ZodPlaceOrderParamsSchema,
1259
1796
  params,
1260
- (message, cause, data) => new ProfileError(message, {
1797
+ (message, cause, data) => new OrdersError(message, {
1261
1798
  code: "VALIDATION_ERROR",
1262
1799
  cause,
1263
- context: { params: data }
1800
+ context: { data }
1264
1801
  })
1265
- ).asyncAndThen(
1266
- (validated) => ResultAsync4.fromPromise(
1267
- publicClient.readContract({
1268
- address: diamondAddress,
1269
- abi: ABIS.DIAMOND,
1270
- functionName: "getRpPerUsdtLimitRational",
1271
- args: [stringToHex2(validated.currency, { size: 32 })]
1272
- }),
1273
- (error) => new ProfileError("Failed to read RP per USDT limit rational", {
1274
- code: "CONTRACT_READ_ERROR",
1275
- cause: error,
1276
- context: { currency: validated.currency, diamondAddress }
1802
+ ).asyncAndThen((v) => {
1803
+ const pcConfigId = v.preferredPaymentChannelConfigId ?? 0n;
1804
+ const circleResult = orderRouter.selectCircle({
1805
+ currency: v.currency,
1806
+ user: v.user,
1807
+ usdtAmount: v.amount,
1808
+ fiatAmount: v.fiatAmount,
1809
+ orderType: BigInt(v.orderType),
1810
+ preferredPCConfigId: pcConfigId
1811
+ }).mapErr(
1812
+ (cause) => new OrdersError(`Circle selection failed: ${cause.message}`, {
1813
+ code: "CIRCLE_SELECTION_FAILED",
1814
+ cause
1277
1815
  })
1278
- ).map(([numerator, denominator]) => ({
1279
- numerator,
1280
- denominator,
1281
- multiplier: numerator > 0n ? Number(denominator) / Number(numerator) : 0
1282
- }))
1283
- );
1816
+ );
1817
+ const identityResult = resolveRelayIdentity({
1818
+ relayIdentity,
1819
+ store: relayIdentityStore
1820
+ });
1821
+ return identityResult.andThen(
1822
+ (senderIdentity) => circleResult.map((circleId) => {
1823
+ const isBuy = v.orderType === ORDER_TYPE.BUY;
1824
+ const keyFromCaller = v.pubKey ?? senderIdentity.publicKey;
1825
+ const pubKey = isBuy ? keyFromCaller : "";
1826
+ const userPubKey = isBuy ? "" : keyFromCaller;
1827
+ const currencyBytes32 = stringToHex2(v.currency, { size: 32 });
1828
+ const data = encodeFunctionData4({
1829
+ abi: ABIS.FACETS.ORDER_FLOW,
1830
+ functionName: "placeOrder",
1831
+ args: [
1832
+ pubKey,
1833
+ v.amount,
1834
+ v.recipientAddr,
1835
+ v.orderType,
1836
+ "",
1837
+ // _userUpi — set later via setSellOrderUpi if applicable
1838
+ userPubKey,
1839
+ currencyBytes32,
1840
+ pcConfigId,
1841
+ circleId,
1842
+ v.fiatAmountLimit ?? 0n
1843
+ ]
1844
+ });
1845
+ return {
1846
+ to: diamondAddress,
1847
+ data,
1848
+ value: 0n,
1849
+ meta: { circleId, relayIdentity: senderIdentity }
1850
+ };
1851
+ })
1852
+ );
1853
+ });
1854
+ return {
1855
+ prepare(params) {
1856
+ return prepareFn(params);
1857
+ },
1858
+ execute({ walletClient, waitForReceipt, ...params }) {
1859
+ const owner = walletClient.account?.address;
1860
+ const enrich = (r) => owner ? enrichWithOrderId(r, owner) : r;
1861
+ return prepareFn(params).andThen(
1862
+ (prepared) => submitPreparedTx({ prepared, walletClient, publicClient, waitForReceipt }).map(enrich)
1863
+ );
1864
+ }
1865
+ };
1284
1866
  }
1285
1867
 
1286
- // src/contracts/usdc/index.ts
1287
- import { ResultAsync as ResultAsync5 } from "neverthrow";
1288
- function getUsdcBalance(publicClient, usdcAddress, params) {
1289
- return validate(
1290
- ZodUsdcBalanceParamsSchema,
1868
+ // src/orders/actions/raise-dispute.ts
1869
+ import { encodeFunctionData as encodeFunctionData5 } from "viem";
1870
+ function createRaiseDisputeAction(input) {
1871
+ const { publicClient, diamondAddress } = input;
1872
+ const prepareFn = (params) => validate(
1873
+ ZodRaiseDisputeParamsSchema,
1291
1874
  params,
1292
- (message, cause, data) => new ProfileError(message, {
1875
+ (message, cause, data) => new OrdersError(message, {
1293
1876
  code: "VALIDATION_ERROR",
1294
1877
  cause,
1295
- context: { params: data }
1878
+ context: { data }
1296
1879
  })
1297
- ).asyncAndThen(
1298
- (validated) => ResultAsync5.fromPromise(
1299
- publicClient.readContract({
1300
- address: usdcAddress,
1301
- abi: ABIS.EXTERNAL.USDC,
1302
- functionName: "balanceOf",
1303
- args: [validated.address]
1304
- }),
1305
- (error) => new ProfileError("Failed to read USDC balance", {
1306
- code: "CONTRACT_READ_ERROR",
1307
- cause: error,
1308
- context: { address: validated.address, usdcAddress }
1309
- })
1310
- )
1311
- );
1312
- }
1313
-
1314
- // src/order-routing/routing.ts
1315
- import { errAsync as errAsync2, okAsync } from "neverthrow";
1316
- var EPSILON = 0.25;
1317
- var RECOVERY_SCALE = 0.3;
1318
- var BOOTSTRAP_MAX_WEIGHT = 25;
1319
- var MAX_VALIDATION_ATTEMPTS = 3;
1320
- function circleWeight(c) {
1321
- const score = c.metrics.circleScore;
1322
- if (c.metrics.circleStatus === "paused") {
1323
- return score * RECOVERY_SCALE;
1324
- }
1325
- if (c.metrics.circleStatus === "bootstrap") {
1326
- return Math.min(score, BOOTSTRAP_MAX_WEIGHT);
1327
- }
1328
- return score;
1329
- }
1330
- function filterEligibleCircles(circles, orderCurrency) {
1331
- return circles.filter((c) => c.currency.toLowerCase() === orderCurrency.toLowerCase());
1332
- }
1333
- function weightedRandomChoice(arr, weights) {
1334
- const totalWeight = weights.reduce((sum, w) => sum + w, 0);
1335
- if (totalWeight === 0) {
1336
- return arr[Math.floor(Math.random() * arr.length)];
1337
- }
1338
- let rand = Math.random() * totalWeight;
1339
- for (let i = 0; i < arr.length; i++) {
1340
- rand -= weights[i];
1341
- if (rand <= 0) {
1342
- return arr[i];
1343
- }
1344
- }
1345
- return arr[arr.length - 1];
1346
- }
1347
- function selectCircle(eligible) {
1348
- if (eligible.length === 0) {
1349
- return null;
1350
- }
1351
- const activeCircles = eligible.filter((c) => c.metrics.circleStatus === "active");
1352
- const isExplore = Math.random() < EPSILON;
1353
- if (isExplore) {
1354
- const weights2 = eligible.map(circleWeight);
1355
- return weightedRandomChoice(eligible, weights2);
1356
- }
1357
- if (activeCircles.length === 0) {
1358
- const weights2 = eligible.map(circleWeight);
1359
- return weightedRandomChoice(eligible, weights2);
1360
- }
1361
- const weights = activeCircles.map((c) => c.metrics.circleScore);
1362
- return weightedRandomChoice(activeCircles, weights);
1363
- }
1364
- function selectCircleForOrderAsync(circles, orderCurrency, validateCircle, logger = noopLogger) {
1365
- const eligible = filterEligibleCircles(circles, orderCurrency);
1366
- let remaining = [...eligible];
1367
- logger.debug("filtering eligible circles", {
1368
- total: circles.length,
1369
- eligible: eligible.length,
1370
- currency: orderCurrency,
1371
- circles: eligible
1372
- });
1373
- if (eligible.length === 0) {
1374
- logger.warn("no eligible circles found for currency", { currency: orderCurrency });
1375
- }
1376
- function attempt(attemptsLeft) {
1377
- if (attemptsLeft <= 0 || remaining.length === 0) {
1378
- logger.warn("exhausted all attempts or circles", {
1379
- attemptsLeft,
1380
- remainingCircles: remaining.length
1381
- });
1382
- return errAsync2(
1383
- new OrderRoutingError("No eligible circles found", {
1384
- code: "NO_ELIGIBLE_CIRCLES"
1385
- })
1386
- );
1387
- }
1388
- const selected = selectCircle(remaining);
1389
- if (!selected) {
1390
- return errAsync2(
1391
- new OrderRoutingError("No eligible circles found", {
1392
- code: "NO_ELIGIBLE_CIRCLES"
1393
- })
1394
- );
1395
- }
1396
- const circleId = BigInt(selected.circleId);
1397
- logger.debug("selected circle, validating on-chain", {
1398
- circleId: String(circleId),
1399
- status: selected.metrics.circleStatus,
1400
- score: selected.metrics.circleScore,
1401
- attemptsLeft
1402
- });
1403
- return validateCircle(circleId).orElse((error) => {
1404
- logger.warn("validation errored, treating as ineligible", {
1405
- circleId: String(circleId),
1406
- error: String(error)
1407
- });
1408
- return okAsync(false);
1409
- }).andThen((isValid) => {
1410
- if (isValid) {
1411
- logger.info("circle validated successfully", { circleId: String(circleId) });
1412
- return okAsync(circleId);
1413
- }
1414
- logger.debug("circle failed validation, retrying", {
1415
- circleId: String(circleId),
1416
- remainingCircles: remaining.length - 1
1417
- });
1418
- remaining = remaining.filter((c) => c.circleId !== selected.circleId);
1419
- return attempt(attemptsLeft - 1);
1420
- });
1421
- }
1422
- return attempt(MAX_VALIDATION_ATTEMPTS);
1423
- }
1424
-
1425
- // src/order-routing/subgraph/client.ts
1426
- import { ResultAsync as ResultAsync6 } from "neverthrow";
1427
- var DEFAULT_TIMEOUT_MS = 1e4;
1428
- var MAX_RETRIES = 3;
1429
- var BACKOFF_MS = 500;
1430
- function isTransient(error) {
1431
- if (error instanceof OrderRoutingError) return false;
1432
- if (error instanceof DOMException && error.name === "AbortError") return true;
1433
- if (error instanceof TypeError) return true;
1434
- return false;
1435
- }
1436
- function querySubgraph(url, params) {
1437
- const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1438
- const fetchOnce = async () => {
1439
- const controller = new AbortController();
1440
- const timer = setTimeout(() => controller.abort(), timeoutMs);
1441
- try {
1442
- const response = await fetch(url, {
1443
- method: "POST",
1444
- headers: { "Content-Type": "application/json" },
1445
- body: JSON.stringify({
1446
- query: params.query,
1447
- variables: params.variables
1448
- }),
1449
- signal: controller.signal
1450
- });
1451
- if (!response.ok) {
1452
- throw new OrderRoutingError(`Subgraph request failed (status: ${response.status})`, {
1453
- code: "SUBGRAPH_ERROR",
1454
- cause: response,
1455
- context: { status: response.status }
1456
- });
1457
- }
1458
- const json = await response.json();
1459
- if (json.errors?.length > 0) {
1460
- throw new OrderRoutingError("Subgraph returned GraphQL errors", {
1461
- code: "SUBGRAPH_ERROR",
1462
- cause: json.errors,
1463
- context: { errors: json.errors }
1464
- });
1465
- }
1466
- if (!json.data) {
1467
- throw new OrderRoutingError("Subgraph returned no data", {
1468
- code: "SUBGRAPH_ERROR",
1469
- cause: "Missing data field in GraphQL response",
1470
- context: { response: json }
1471
- });
1472
- }
1473
- return json.data;
1474
- } finally {
1475
- clearTimeout(timer);
1476
- }
1477
- };
1478
- const fetchWithRetry = async () => {
1479
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
1480
- try {
1481
- return await fetchOnce();
1482
- } catch (error) {
1483
- const lastAttempt = attempt === MAX_RETRIES;
1484
- if (lastAttempt || !isTransient(error)) throw error;
1485
- await sleep(BACKOFF_MS * (attempt + 1));
1486
- }
1487
- }
1488
- throw new OrderRoutingError("Subgraph query exhausted retries", {
1489
- code: "SUBGRAPH_ERROR"
1490
- });
1491
- };
1492
- return ResultAsync6.fromPromise(
1493
- fetchWithRetry(),
1494
- (error) => error instanceof OrderRoutingError ? error : new OrderRoutingError("Subgraph query failed", {
1495
- code: "SUBGRAPH_ERROR",
1496
- cause: error
1497
- })
1498
- );
1499
- }
1500
-
1501
- // src/order-routing/subgraph/queries.ts
1502
- var CIRCLES_FOR_ROUTING_QUERY = (
1503
- /* GraphQL */
1504
- `
1505
- query CirclesForRouting($currency: Bytes!) {
1506
- circles(
1507
- first: 1000
1508
- where: {
1509
- currency: $currency
1510
- metrics_: {
1511
- circleStatus_in: ["active", "bootstrap", "paused"]
1512
- }
1513
- }
1514
- ) {
1515
- circleId
1516
- currency
1517
- metrics {
1518
- circleScore
1519
- circleStatus
1520
- scoreState {
1521
- activeMerchantsCount
1522
- }
1523
- }
1524
- }
1525
- }
1526
- `
1527
- );
1528
-
1529
- // src/order-routing/subgraph/index.ts
1530
- function getCirclesForRouting(subgraphUrl, currency, logger = noopLogger) {
1531
- logger.debug("fetching circles from subgraph", { subgraphUrl, currency });
1532
- return querySubgraph(subgraphUrl, {
1533
- query: CIRCLES_FOR_ROUTING_QUERY,
1534
- variables: { currency }
1535
- }).andThen(
1536
- (data) => validate(
1537
- ZodCirclesForRoutingResponseSchema,
1538
- data,
1539
- (message, cause, d) => new OrderRoutingError(message, { code: "VALIDATION_ERROR", cause, context: { data: d } })
1540
- ).map((validated) => {
1541
- const circles = validated.circles.filter(
1542
- (item) => Number(item.metrics.scoreState.activeMerchantsCount) > 0
1543
- );
1544
- logger.info("fetched circles from subgraph", {
1545
- total: validated.circles.length,
1546
- withActiveMerchants: circles.length,
1547
- circles
1548
- });
1549
- return circles;
1550
- })
1551
- );
1552
- }
1553
-
1554
- // src/order-routing/client.ts
1555
- function createOrderRouter(config) {
1556
- const { subgraphUrl, publicClient, contractAddress } = config;
1557
- const logger = config.logger ?? noopLogger;
1880
+ ).map(({ orderId, redactTransId }) => ({
1881
+ to: diamondAddress,
1882
+ data: encodeFunctionData5({
1883
+ abi: ABIS.FACETS.ORDER_PROCESSOR,
1884
+ functionName: "raiseDispute",
1885
+ args: [orderId, redactTransId]
1886
+ }),
1887
+ value: 0n
1888
+ }));
1558
1889
  return {
1559
- selectCircle(params) {
1560
- const currencyHex = stringToHex3(params.currency, { size: 32 });
1561
- logger.info("selectCircle started", {
1562
- currency: params.currency,
1563
- user: params.user,
1564
- orderType: String(params.orderType)
1565
- });
1566
- return getCirclesForRouting(subgraphUrl, currencyHex, logger).andThen(
1567
- (circles) => selectCircleForOrderAsync(
1568
- circles,
1569
- currencyHex,
1570
- (circleId) => checkCircleEligibility(
1571
- publicClient,
1572
- contractAddress,
1573
- {
1574
- circleId,
1575
- currency: currencyHex,
1576
- user: params.user,
1577
- usdtAmount: params.usdtAmount,
1578
- fiatAmount: params.fiatAmount,
1579
- orderType: params.orderType,
1580
- preferredPCConfigId: params.preferredPCConfigId
1581
- },
1582
- logger
1583
- ),
1584
- logger
1585
- )
1890
+ prepare(params) {
1891
+ return prepareFn(params).asyncMap(async (tx) => tx);
1892
+ },
1893
+ execute({ walletClient, waitForReceipt, ...params }) {
1894
+ return prepareFn(params).asyncAndThen(
1895
+ (prepared) => submitPreparedTx({ prepared, walletClient, publicClient, waitForReceipt })
1586
1896
  );
1587
1897
  }
1588
1898
  };
1589
1899
  }
1590
1900
 
1591
- // src/payload/actions.ts
1592
- import { errAsync as errAsync3 } from "neverthrow";
1901
+ // src/orders/actions/set-sell-order-upi.ts
1902
+ import { encodeFunctionData as encodeFunctionData6 } from "viem";
1593
1903
 
1594
- // src/payload/crypto.ts
1595
- import { ok as ok4, Result as Result2, ResultAsync as ResultAsync7, safeTry } from "neverthrow";
1596
- import { keccak256, serializeSignature, stringToHex as stringToHex4 } from "viem";
1904
+ // src/orders/crypto/encryption.ts
1905
+ import { ok as ok4, Result, ResultAsync as ResultAsync6, safeTry } from "neverthrow";
1906
+ import { keccak256, serializeSignature, stringToHex as stringToHex3 } from "viem";
1597
1907
  import { sign } from "viem/accounts";
1598
- import { z as z7 } from "zod";
1908
+ import { z as z5 } from "zod";
1599
1909
 
1600
1910
  // node_modules/@noble/ciphers/esm/utils.js
1601
1911
  function isBytes(a) {
@@ -3544,15 +3854,15 @@ function weierstrassPoints(opts) {
3544
3854
  throw new Error("ProjectivePoint expected");
3545
3855
  }
3546
3856
  const toAffineMemo = memoized((p, iz) => {
3547
- const { px: x, py: y, pz: z9 } = p;
3548
- if (Fp.eql(z9, Fp.ONE))
3857
+ const { px: x, py: y, pz: z10 } = p;
3858
+ if (Fp.eql(z10, Fp.ONE))
3549
3859
  return { x, y };
3550
3860
  const is0 = p.is0();
3551
3861
  if (iz == null)
3552
- iz = is0 ? Fp.ONE : Fp.inv(z9);
3862
+ iz = is0 ? Fp.ONE : Fp.inv(z10);
3553
3863
  const ax = Fp.mul(x, iz);
3554
3864
  const ay = Fp.mul(y, iz);
3555
- const zz = Fp.mul(z9, iz);
3865
+ const zz = Fp.mul(z10, iz);
3556
3866
  if (is0)
3557
3867
  return { x: Fp.ZERO, y: Fp.ZERO };
3558
3868
  if (!Fp.eql(zz, Fp.ONE))
@@ -4313,7 +4623,8 @@ var sha2562 = sha256;
4313
4623
  // node_modules/@noble/hashes/esm/sha512.js
4314
4624
  var sha5122 = sha512;
4315
4625
 
4316
- // src/payload/ecies.ts
4626
+ // src/orders/crypto/ecies.ts
4627
+ var MIN_CIPHER_BYTES = 82;
4317
4628
  function hexToBytes3(hex) {
4318
4629
  const bytes = new Uint8Array(hex.length / 2);
4319
4630
  for (let i = 0; i < bytes.length; i++) {
@@ -4326,242 +4637,1746 @@ function bytesToHex2(bytes) {
4326
4637
  for (const b of bytes) {
4327
4638
  hex += b.toString(16).padStart(2, "0");
4328
4639
  }
4329
- return hex;
4330
- }
4331
- function deriveKeys(sharedSecret) {
4332
- const hash = sha5122(sharedSecret);
4333
- return {
4334
- encKey: hash.slice(0, 32),
4335
- macKey: hash.slice(32)
4336
- };
4640
+ return hex;
4641
+ }
4642
+ function timingSafeEqual(a, b) {
4643
+ if (a.length !== b.length) return false;
4644
+ let diff = 0;
4645
+ for (let i = 0; i < a.length; i++) {
4646
+ diff |= a[i] ^ b[i];
4647
+ }
4648
+ return diff === 0;
4649
+ }
4650
+ function deriveKeys(sharedSecret) {
4651
+ const hash = sha5122(sharedSecret);
4652
+ return {
4653
+ encKey: hash.slice(0, 32),
4654
+ macKey: hash.slice(32)
4655
+ };
4656
+ }
4657
+ async function encryptWithPublicKey(publicKey, message) {
4658
+ const pubKeyBytes = hexToBytes3(`04${publicKey}`);
4659
+ const ephemPrivKey = randomBytes(32);
4660
+ const ephemPubKey = secp256k1.getPublicKey(ephemPrivKey, false);
4661
+ const sharedPoint = secp256k1.getSharedSecret(ephemPrivKey, pubKeyBytes, true);
4662
+ const sharedSecret = sharedPoint.slice(1);
4663
+ const { encKey, macKey } = deriveKeys(sharedSecret);
4664
+ const iv = randomBytes(16);
4665
+ const plaintext = new TextEncoder().encode(message);
4666
+ const cipher = cbc(encKey, iv);
4667
+ const ciphertext = cipher.encrypt(plaintext);
4668
+ const macData = concatBytes2(iv, ephemPubKey, ciphertext);
4669
+ const mac = hmac(sha2562, macKey, macData);
4670
+ return {
4671
+ iv: bytesToHex2(iv),
4672
+ ephemPublicKey: bytesToHex2(ephemPubKey),
4673
+ ciphertext: bytesToHex2(ciphertext),
4674
+ mac: bytesToHex2(mac)
4675
+ };
4676
+ }
4677
+ async function decryptWithPrivateKey(privateKey, encrypted) {
4678
+ const privKeyBytes = hexToBytes3(privateKey.replace(/^0x/, ""));
4679
+ const ephemPubKeyBytes = hexToBytes3(encrypted.ephemPublicKey);
4680
+ const ivBytes = hexToBytes3(encrypted.iv);
4681
+ const ciphertextBytes = hexToBytes3(encrypted.ciphertext);
4682
+ const macBytes = hexToBytes3(encrypted.mac);
4683
+ const sharedPoint = secp256k1.getSharedSecret(privKeyBytes, ephemPubKeyBytes, true);
4684
+ const sharedSecret = sharedPoint.slice(1);
4685
+ const { encKey, macKey } = deriveKeys(sharedSecret);
4686
+ const macData = concatBytes2(ivBytes, ephemPubKeyBytes, ciphertextBytes);
4687
+ const computedMac = hmac(sha2562, macKey, macData);
4688
+ if (!timingSafeEqual(computedMac, macBytes)) {
4689
+ throw new Error("MAC mismatch \u2014 ciphertext may be corrupted or tampered with");
4690
+ }
4691
+ const cipher = cbc(encKey, ivBytes);
4692
+ const plaintext = cipher.decrypt(ciphertextBytes);
4693
+ return new TextDecoder().decode(plaintext);
4694
+ }
4695
+ function cipherStringify(encrypted) {
4696
+ const ephemPubKeyBytes = hexToBytes3(encrypted.ephemPublicKey);
4697
+ const compressed = secp256k1.ProjectivePoint.fromHex(ephemPubKeyBytes).toRawBytes(true);
4698
+ const iv = hexToBytes3(encrypted.iv);
4699
+ const mac = hexToBytes3(encrypted.mac);
4700
+ const ciphertext = hexToBytes3(encrypted.ciphertext);
4701
+ return bytesToHex2(concatBytes2(iv, compressed, mac, ciphertext));
4702
+ }
4703
+ function cipherParse(str) {
4704
+ const buf = hexToBytes3(str);
4705
+ if (buf.length < MIN_CIPHER_BYTES) {
4706
+ throw new Error(
4707
+ `cipherParse: input too short (${buf.length} bytes, need at least ${MIN_CIPHER_BYTES})`
4708
+ );
4709
+ }
4710
+ const iv = buf.slice(0, 16);
4711
+ const compressed = buf.slice(16, 49);
4712
+ const mac = buf.slice(49, 81);
4713
+ const ciphertext = buf.slice(81);
4714
+ const ephemPubKey = secp256k1.ProjectivePoint.fromHex(compressed).toRawBytes(false);
4715
+ return {
4716
+ iv: bytesToHex2(iv),
4717
+ ephemPublicKey: bytesToHex2(ephemPubKey),
4718
+ ciphertext: bytesToHex2(ciphertext),
4719
+ mac: bytesToHex2(mac)
4720
+ };
4721
+ }
4722
+
4723
+ // src/orders/crypto/encryption.ts
4724
+ function tryParseLegacyEthCryptoEnvelope(input) {
4725
+ if (input.charCodeAt(0) !== 123) return void 0;
4726
+ let parsed;
4727
+ try {
4728
+ parsed = JSON.parse(input);
4729
+ } catch {
4730
+ return void 0;
4731
+ }
4732
+ if (!parsed || typeof parsed !== "object") return void 0;
4733
+ const o = parsed;
4734
+ if (typeof o.iv !== "string" || typeof o.ephemPublicKey !== "string" || typeof o.ciphertext !== "string" || typeof o.mac !== "string") {
4735
+ return void 0;
4736
+ }
4737
+ return {
4738
+ iv: o.iv,
4739
+ ephemPublicKey: o.ephemPublicKey,
4740
+ ciphertext: o.ciphertext,
4741
+ mac: o.mac
4742
+ };
4743
+ }
4744
+ function encryptPaymentAddress(input) {
4745
+ return safeTry(async function* () {
4746
+ const messageHash = keccak256(stringToHex3(input.paymentAddress));
4747
+ const signature = yield* ResultAsync6.fromPromise(
4748
+ sign({ hash: messageHash, privateKey: input.senderIdentity.privateKey }),
4749
+ (cause) => new OrdersError("Failed to sign payment address", {
4750
+ code: "ENCRYPTION_FAILED",
4751
+ cause
4752
+ })
4753
+ ).map(serializeSignature);
4754
+ const payload = JSON.stringify({ message: input.paymentAddress, signature });
4755
+ const encrypted = yield* ResultAsync6.fromPromise(
4756
+ encryptWithPublicKey(input.recipientPublicKey, payload),
4757
+ (cause) => new OrdersError("ECIES encryption failed", {
4758
+ code: "ENCRYPTION_FAILED",
4759
+ cause
4760
+ })
4761
+ );
4762
+ const safeStringify = Result.fromThrowable(
4763
+ (e) => cipherStringify(e),
4764
+ (cause) => new OrdersError("Ciphertext stringify failed", {
4765
+ code: "ENCRYPTION_FAILED",
4766
+ cause
4767
+ })
4768
+ );
4769
+ return ok4(yield* safeStringify(encrypted));
4770
+ });
4771
+ }
4772
+ var ZodDecryptedPayloadSchema = z5.object({
4773
+ message: z5.string(),
4774
+ signature: z5.string()
4775
+ });
4776
+ function decryptPaymentAddress(input) {
4777
+ return safeTry(async function* () {
4778
+ const legacyEnvelope = tryParseLegacyEthCryptoEnvelope(input.encrypted);
4779
+ const safeCipherParse = Result.fromThrowable(
4780
+ (s) => cipherParse(s),
4781
+ (cause) => new OrdersError("Failed to parse ciphertext", {
4782
+ code: "ENCRYPTION_FAILED",
4783
+ cause
4784
+ })
4785
+ );
4786
+ const encryptedData = legacyEnvelope ?? (yield* safeCipherParse(input.encrypted));
4787
+ const plaintext = yield* ResultAsync6.fromPromise(
4788
+ decryptWithPrivateKey(input.recipientIdentity.privateKey, encryptedData),
4789
+ (cause) => new OrdersError("ECIES decryption failed", {
4790
+ code: "ENCRYPTION_FAILED",
4791
+ cause
4792
+ })
4793
+ );
4794
+ if (legacyEnvelope) {
4795
+ return ok4(plaintext);
4796
+ }
4797
+ const safeJsonParse = Result.fromThrowable(
4798
+ (s) => JSON.parse(s),
4799
+ (cause) => new OrdersError("Failed to parse decrypted payload JSON", {
4800
+ code: "ENCRYPTION_FAILED",
4801
+ cause
4802
+ })
4803
+ );
4804
+ const parsed = yield* safeJsonParse(plaintext);
4805
+ const payload = yield* validate(
4806
+ ZodDecryptedPayloadSchema,
4807
+ parsed,
4808
+ (message, cause, data) => new OrdersError(message, {
4809
+ code: "ENCRYPTION_FAILED",
4810
+ cause,
4811
+ context: { data }
4812
+ })
4813
+ );
4814
+ return ok4(payload.message);
4815
+ });
4816
+ }
4817
+
4818
+ // src/orders/actions/set-sell-order-upi.ts
4819
+ function createSetSellOrderUpiAction(input) {
4820
+ const { publicClient, diamondAddress, relayIdentityStore, relayIdentity } = input;
4821
+ const prepareFn = (params) => validate(
4822
+ ZodSetSellOrderUpiParamsSchema,
4823
+ params,
4824
+ (message, cause, data) => new OrdersError(message, {
4825
+ code: "VALIDATION_ERROR",
4826
+ cause,
4827
+ context: { data }
4828
+ })
4829
+ ).asyncAndThen(
4830
+ (v) => resolveRelayIdentity({ relayIdentity, store: relayIdentityStore }).andThen(
4831
+ (senderIdentity) => encryptPaymentAddress({
4832
+ paymentAddress: v.paymentAddress,
4833
+ recipientPublicKey: v.merchantPublicKey,
4834
+ senderIdentity
4835
+ }).map((userEncUpi) => ({ v, userEncUpi, senderIdentity }))
4836
+ )
4837
+ ).map(({ v, userEncUpi, senderIdentity }) => ({
4838
+ to: diamondAddress,
4839
+ data: encodeFunctionData6({
4840
+ abi: ABIS.FACETS.ORDER_FLOW,
4841
+ functionName: "setSellOrderUpi",
4842
+ args: [v.orderId, userEncUpi, v.updatedAmount]
4843
+ }),
4844
+ value: 0n,
4845
+ meta: { relayIdentity: senderIdentity }
4846
+ }));
4847
+ return {
4848
+ prepare(params) {
4849
+ return prepareFn(params);
4850
+ },
4851
+ execute({ walletClient, waitForReceipt, ...params }) {
4852
+ return prepareFn(params).andThen(
4853
+ (prepared) => submitPreparedTx({ prepared, walletClient, publicClient, waitForReceipt })
4854
+ );
4855
+ }
4856
+ };
4857
+ }
4858
+
4859
+ // src/orders/internal/routing/client.ts
4860
+ import { stringToHex as stringToHex6 } from "viem";
4861
+
4862
+ // src/contracts/errors.ts
4863
+ var contractErrors = {
4864
+ // Access control
4865
+ NotAdmin: "NOT_ADMIN",
4866
+ NotSuperAdmin: "NOT_SUPER_ADMIN",
4867
+ NotAuthorized: "NOT_AUTHORIZED",
4868
+ NotSelf: "NOT_SELF",
4869
+ NotWhitelisted: "NOT_WHITELISTED",
4870
+ NotCircleAdmin: "NOT_CIRCLE_ADMIN",
4871
+ // Circle / community management
4872
+ InvalidName: "INVALID_NAME",
4873
+ InvalidCommunityUrl: "INVALID_COMMUNITY_URL",
4874
+ InvalidAdminCommunityUrl: "INVALID_ADMIN_COMMUNITY_URL",
4875
+ AdminAlreadyHasCircle: "ADMIN_ALREADY_HAS_CIRCLE",
4876
+ CircleNameAlreadyTaken: "CIRCLE_NAME_ALREADY_TAKEN",
4877
+ P2PStakeConfigNotSet: "P2P_STAKE_CONFIG_NOT_SET",
4878
+ InsufficientP2PStake: "INSUFFICIENT_P2P_STAKE",
4879
+ P2PTokenNotSet: "P2P_TOKEN_NOT_SET",
4880
+ P2PUnstakeRequestPending: "P2P_UNSTAKE_REQUEST_PENDING",
4881
+ NoP2PUnstakeRequest: "NO_P2P_UNSTAKE_REQUEST",
4882
+ P2PUnstakeCooldownNotPassed: "P2P_UNSTAKE_COOLDOWN_NOT_PASSED",
4883
+ SlashAmountExceedsStake: "SLASH_AMOUNT_EXCEEDS_STAKE",
4884
+ CircleNotActive: "CIRCLE_NOT_ACTIVE",
4885
+ InvalidCircleId: "INVALID_CIRCLE_ID",
4886
+ CurrencyMismatch: "CURRENCY_MISMATCH",
4887
+ CircleFull: "CIRCLE_FULL",
4888
+ CircleIdMismatch: "CIRCLE_ID_MISMATCH",
4889
+ DuplicateAccountName: "DUPLICATE_ACCOUNT_NAME",
4890
+ EmptyName: "EMPTY_NAME",
4891
+ AccountBoundToAnotherCircle: "ACCOUNT_BOUND_TO_ANOTHER_CIRCLE",
4892
+ ExitAmountExceededCircleBalance: "EXIT_AMOUNT_EXCEEDED_CIRCLE_BALANCE",
4893
+ UndelegationAmountTooHigh: "UNDELEGATION_AMOUNT_TOO_HIGH",
4894
+ // Exchange / order lifecycle
4895
+ ExchangeNotOperational: "EXCHANGE_NOT_OPERATIONAL",
4896
+ OrderNotPlaced: "ORDER_NOT_PLACED",
4897
+ OrderNotPaid: "ORDER_NOT_PAID",
4898
+ OrderStatusInvalid: "ORDER_STATUS_INVALID",
4899
+ OrderExpired: "ORDER_EXPIRED",
4900
+ OrderAlreadyPaid: "ORDER_ALREADY_PAID",
4901
+ OrderAlreadyCompleted: "ORDER_ALREADY_COMPLETED",
4902
+ InvalidOrderType: "INVALID_ORDER_TYPE",
4903
+ OrderTypeIncorrect: "ORDER_TYPE_INCORRECT",
4904
+ OrderNotAccepted: "ORDER_NOT_ACCEPTED",
4905
+ OrderNotAssigned: "ORDER_NOT_ASSIGNED",
4906
+ OrderAmountExceedsLimit: "ORDER_AMOUNT_EXCEEDS_LIMIT",
4907
+ InvalidOrderAmount: "INVALID_ORDER_AMOUNT",
4908
+ InvalidOrderAmountToCoverFee: "INVALID_ORDER_AMOUNT_TO_COVER_FEE",
4909
+ InvalidOrderId: "INVALID_ORDER_ID",
4910
+ OrderTooEarlyForReassignment: "ORDER_TOO_EARLY_FOR_REASSIGNMENT",
4911
+ OrderTooLateForReassignment: "ORDER_TOO_LATE_FOR_REASSIGNMENT",
4912
+ ReAssignmentNotRequired: "REASSIGNMENT_NOT_REQUIRED",
4913
+ TipAlreadyGiven: "TIP_ALREADY_GIVEN",
4914
+ CashbackTransferFailed: "CASHBACK_TRANSFER_FAILED",
4915
+ // Order limits
4916
+ DailyBuyOrderLimitExceeded: "DAILY_BUY_ORDER_LIMIT_EXCEEDED",
4917
+ MonthlyBuyOrderLimitExceeded: "MONTHLY_BUY_ORDER_LIMIT_EXCEEDED",
4918
+ SellOrderAmountLimitExceeded: "SELL_ORDER_AMOUNT_LIMIT_EXCEEDED",
4919
+ BuyOrderAmountExceedsLimit: "BUY_ORDER_AMOUNT_EXCEEDS_LIMIT",
4920
+ SellOrderAmountExceedsLimit: "SELL_ORDER_AMOUNT_EXCEEDS_LIMIT",
4921
+ BuyAmountExceedsUsdcLimit: "BUY_AMOUNT_EXCEEDS_USDC_LIMIT",
4922
+ SellAmountExceedsFiatLimit: "SELL_AMOUNT_EXCEEDS_FIAT_LIMIT",
4923
+ DailyVolumeLimitExceeded: "DAILY_VOLUME_LIMIT_EXCEEDED",
4924
+ MonthlyVolumeLimitExceeded: "MONTHLY_VOLUME_LIMIT_EXCEEDED",
4925
+ UserYearlyVolumeLimitExceeded: "USER_YEARLY_VOLUME_LIMIT_EXCEEDED",
4926
+ // Dispute
4927
+ DisputeTimeNotReached: "DISPUTE_TIME_NOT_REACHED",
4928
+ DisputeTimeExpired: "DISPUTE_TIME_EXPIRED",
4929
+ InvalidOrderStatusToRaiseDispute: "INVALID_ORDER_STATUS_TO_RAISE_DISPUTE",
4930
+ DisputeNotRaised: "DISPUTE_NOT_RAISED",
4931
+ CannotRaiseDisputeTwice: "CANNOT_RAISE_DISPUTE_TWICE",
4932
+ DisputeAlreadySettled: "DISPUTE_ALREADY_SETTLED",
4933
+ TransactionIdMismatch: "TRANSACTION_ID_MISMATCH",
4934
+ AccountNumberMismatch: "ACCOUNT_NUMBER_MISMATCH",
4935
+ NotPaidBuyOrder: "NOT_PAID_BUY_ORDER",
4936
+ // Payment channels
4937
+ PaymentChannelNotFound: "PAYMENT_CHANNEL_NOT_FOUND",
4938
+ PaymentChannelNotActive: "PAYMENT_CHANNEL_NOT_ACTIVE",
4939
+ PaymentChannelNotApproved: "PAYMENT_CHANNEL_NOT_APPROVED",
4940
+ PaymentChannelNotRejected: "PAYMENT_CHANNEL_NOT_REJECTED",
4941
+ InvalidPaymentChannelId: "INVALID_PAYMENT_CHANNEL_ID",
4942
+ DuplicatePaymentChannel: "DUPLICATE_PAYMENT_CHANNEL",
4943
+ OldPaymentChannelNotFound: "OLD_PAYMENT_CHANNEL_NOT_FOUND",
4944
+ NewPaymentChannelNotFound: "NEW_PAYMENT_CHANNEL_NOT_FOUND",
4945
+ SamePaymentChannel: "SAME_PAYMENT_CHANNEL",
4946
+ OldPaymentChannelShouldBeInactive: "OLD_PAYMENT_CHANNEL_SHOULD_BE_INACTIVE",
4947
+ NewPaymentChannelShouldBeActive: "NEW_PAYMENT_CHANNEL_SHOULD_BE_ACTIVE",
4948
+ OngoingOrderOnPaymentChannel: "ONGOING_ORDER_ON_PAYMENT_CHANNEL",
4949
+ UpiAlreadySent: "UPI_ALREADY_SENT",
4950
+ InvalidOrderUpi: "INVALID_ORDER_UPI",
4951
+ NoFiatLiquidity: "NO_FIAT_LIQUIDITY",
4952
+ // Merchant
4953
+ NotEnoughEligibleMerchants: "NOT_ENOUGH_ELIGIBLE_MERCHANTS",
4954
+ MerchantNotRegistered: "MERCHANT_NOT_REGISTERED",
4955
+ MerchantNotApproved: "MERCHANT_NOT_APPROVED",
4956
+ MerchantAlreadyRegistered: "MERCHANT_ALREADY_REGISTERED",
4957
+ MerchantAlreadyRejected: "MERCHANT_ALREADY_REJECTED",
4958
+ MerchantBlacklisted: "MERCHANT_BLACKLISTED",
4959
+ MerchantNotBlacklisted: "MERCHANT_NOT_BLACKLISTED",
4960
+ MerchantAlreadyBlacklisted: "MERCHANT_ALREADY_BLACKLISTED",
4961
+ MerchantHasOngoingOrders: "MERCHANT_HAS_ONGOING_ORDERS",
4962
+ MerchantNotFullfilledEligibilityThreshold: "MERCHANT_NOT_FULLFILLED_ELIGIBILITY_THRESHOLD",
4963
+ InvalidMerchant: "INVALID_MERCHANT",
4964
+ // Staking / unstaking
4965
+ StakeAmountTooLow: "STAKE_AMOUNT_TOO_LOW",
4966
+ AdditionalStakeNotAllowed: "ADDITIONAL_STAKE_NOT_ALLOWED",
4967
+ UnstakeRequestPending: "UNSTAKE_REQUEST_PENDING",
4968
+ UnstakeRequestNotPending: "UNSTAKE_REQUEST_NOT_PENDING",
4969
+ UnstakeAmountExceeded: "UNSTAKE_AMOUNT_EXCEEDED",
4970
+ ZeroUnstakeAmount: "ZERO_UNSTAKE_AMOUNT",
4971
+ NoWithdrawableAmount: "NO_WITHDRAWABLE_AMOUNT",
4972
+ NoStake: "NO_STAKE",
4973
+ NoStakers: "NO_STAKERS",
4974
+ InsufficientStakedAmount: "INSUFFICIENT_STAKED_AMOUNT",
4975
+ CooldownNotPassed: "COOLDOWN_NOT_PASSED",
4976
+ ClaimableRewardsNotAvailable: "CLAIMABLE_REWARDS_NOT_AVAILABLE",
4977
+ // Delegation
4978
+ ExitWouldBreachDelegationInvariant: "EXIT_WOULD_BREACH_DELEGATION_INVARIANT",
4979
+ AggregateDelegationExceedsTotalStaked: "AGGREGATE_DELEGATION_EXCEEDS_TOTAL_STAKED",
4980
+ InsufficientMerchantRewards: "INSUFFICIENT_MERCHANT_REWARDS",
4981
+ // Migration
4982
+ InvalidMigrationStatus: "INVALID_MIGRATION_STATUS",
4983
+ MigrationRequestNotPending: "MIGRATION_REQUEST_NOT_PENDING",
4984
+ MigrationAlreadyRequested: "MIGRATION_ALREADY_REQUESTED",
4985
+ // Token / currency
4986
+ TokenAlreadyExists: "TOKEN_ALREADY_EXISTS",
4987
+ TokenNotFound: "TOKEN_NOT_FOUND",
4988
+ TokenEmpty: "TOKEN_EMPTY",
4989
+ CurrencyNotSupported: "CURRENCY_NOT_SUPPORTED",
4990
+ InvalidCurrency: "INVALID_CURRENCY",
4991
+ // USDC / transfer
4992
+ UsdtTransferFailed: "USDC_TRANSFER_FAILED",
4993
+ UsdtTransferFailedWithErrorMessage: "USDC_TRANSFER_FAILED_WITH_ERROR_MESSAGE",
4994
+ UsdtTransferFailedWithPanic: "USDC_TRANSFER_FAILED_WITH_PANIC",
4995
+ InsufficientAllowance: "INSUFFICIENT_ALLOWANCE",
4996
+ // ZK Passport
4997
+ ZKPassportVerifierNotSet: "ZK_PASSPORT_VERIFIER_NOT_SET",
4998
+ ZKPassportDomainEmpty: "ZK_PASSPORT_DOMAIN_EMPTY",
4999
+ ZKPassportScopeEmpty: "ZK_PASSPORT_SCOPE_EMPTY",
5000
+ PassportAlreadyVerified: "PASSPORT_ALREADY_VERIFIED",
5001
+ ZKPassportProofInvalid: "ZK_PASSPORT_PROOF_INVALID",
5002
+ ZKPassportIdentifierAlreadyVerified: "ZK_PASSPORT_IDENTIFIER_ALREADY_VERIFIED",
5003
+ ZKPassportInvalidScope: "ZK_PASSPORT_INVALID_SCOPE",
5004
+ ZKPassportUnexpectedSender: "ZK_PASSPORT_UNEXPECTED_SENDER",
5005
+ ZKPassportAgeBelowMinimum: "ZK_PASSPORT_AGE_BELOW_MINIMUM",
5006
+ ZKPassportMinAgeTooHigh: "ZK_PASSPORT_MIN_AGE_TOO_HIGH",
5007
+ // Chainlink / oracle
5008
+ UnexpectedRequestId: "UNEXPECTED_REQUEST_ID",
5009
+ OnlyRouterCanFulfill: "ONLY_ROUTER_CAN_FULFILL",
5010
+ RequestFailed: "REQUEST_FAILED",
5011
+ SourceCodeMismatch: "SOURCE_CODE_MISMATCH",
5012
+ ZeroMarketPrice: "ZERO_MARKET_PRICE",
5013
+ InvalidComputedPrices: "INVALID_COMPUTED_PRICES",
5014
+ NotPriceUpdaterForCurrency: "NOT_PRICE_UPDATER_FOR_CURRENCY",
5015
+ ThresholdNotConfigured: "THRESHOLD_NOT_CONFIGURED",
5016
+ SlippageExceeded: "SLIPPAGE_EXCEEDED",
5017
+ // Reputation / verification
5018
+ UserHasNoReputation: "USER_HAS_NO_REPUTATION",
5019
+ ZeroReputationPoints: "ZERO_REPUTATION_POINTS",
5020
+ NoReputation: "NO_REPUTATION",
5021
+ InsufficientRP: "INSUFFICIENT_RP",
5022
+ NullifierAlreadyVerified: "NULLIFIER_ALREADY_VERIFIED",
5023
+ VerificationFailed: "VERIFICATION_FAILED",
5024
+ InvalidSocialPlatform: "INVALID_SOCIAL_PLATFORM",
5025
+ SocialAlreadyVerified: "SOCIAL_ALREADY_VERIFIED",
5026
+ YearFieldNotInProof: "YEAR_FIELD_NOT_IN_PROOF",
5027
+ UserIdFieldNotInProof: "USER_ID_FIELD_NOT_IN_PROOF",
5028
+ UserIdAlreadyVerified: "USER_ID_ALREADY_VERIFIED",
5029
+ UsernameAlreadyVerified: "USERNAME_ALREADY_VERIFIED",
5030
+ UsernameNotInProof: "USERNAME_NOT_IN_PROOF",
5031
+ LinkedInOnlyRpUpdates: "LINKEDIN_ONLY_RP_UPDATES",
5032
+ FacebookOnlyRpUpdates: "FACEBOOK_ONLY_RP_UPDATES",
5033
+ // Voting / referral
5034
+ AlreadyReferred: "ALREADY_REFERRED",
5035
+ SelfReferralNotAllowed: "SELF_REFERRAL_NOT_ALLOWED",
5036
+ NotEligibleToRefer: "NOT_ELIGIBLE_TO_REFER",
5037
+ MerchantMonthlyReferralLimitReached: "MERCHANT_MONTHLY_REFERRAL_LIMIT_REACHED",
5038
+ NoRecommender: "NO_RECOMMENDER",
5039
+ RecommendationAlreadyClaimed: "RECOMMENDATION_ALREADY_CLAIMED",
5040
+ CannotVoteYourself: "CANNOT_VOTE_YOURSELF",
5041
+ VotesPerEpochExceeded: "VOTES_PER_EPOCH_EXCEEDED",
5042
+ AlreadyVoted: "ALREADY_VOTED",
5043
+ FunctionNotFound: "FUNCTION_NOT_FOUND",
5044
+ // Campaign
5045
+ CampaignNotActive: "CAMPAIGN_NOT_ACTIVE",
5046
+ InvalidManagerDetails: "INVALID_MANAGER_DETAILS",
5047
+ UnclaimedRewardsExist: "UNCLAIMED_REWARDS_EXIST",
5048
+ RewardAlreadyClaimed: "REWARD_ALREADY_CLAIMED",
5049
+ OnlyNewUsersAllowed: "ONLY_NEW_USERS_ALLOWED",
5050
+ ManagerNotFound: "MANAGER_NOT_FOUND",
5051
+ ManagerInactive: "MANAGER_INACTIVE",
5052
+ NoRewards: "NO_REWARDS",
5053
+ InvalidCampaignId: "INVALID_CAMPAIGN_ID",
5054
+ CannotClaimRevenueForCurrentMonth: "CANNOT_CLAIM_REVENUE_FOR_CURRENT_MONTH",
5055
+ // Referral reward config
5056
+ RewardPercentageTooHigh: "REWARD_PERCENTAGE_TOO_HIGH",
5057
+ // Signature / nonce
5058
+ NonceAlreadyUsed: "NONCE_ALREADY_USED",
5059
+ SignatureValidationFailed: "SIGNATURE_VALIDATION_FAILED",
5060
+ // Misc
5061
+ InvalidAddress: "INVALID_ADDRESS",
5062
+ InvalidBlockAmount: "INVALID_BLOCK_AMOUNT",
5063
+ InvalidAmount: "INVALID_AMOUNT",
5064
+ InvalidInput: "INVALID_INPUT",
5065
+ InvalidStatusTransition: "INVALID_STATUS_TRANSITION",
5066
+ ArrayLengthMismatch: "ARRAY_LENGTH_MISMATCH",
5067
+ UserIsBlacklisted: "USER_IS_BLACKLISTED",
5068
+ ZeroAddress: "ZERO_ADDRESS",
5069
+ ReentrancyGuard: "REENTRANCY_GUARD",
5070
+ BatchTooLarge: "BATCH_TOO_LARGE",
5071
+ UnderflowSubtraction: "UNDERFLOW_SUBTRACTION",
5072
+ TargetLongerThanData: "TARGET_LONGER_THAN_DATA"
5073
+ };
5074
+ var hexContractErrors = {
5075
+ // Access control
5076
+ "0x7bfa4b9f": contractErrors.NotAdmin,
5077
+ "0x16c726b1": contractErrors.NotSuperAdmin,
5078
+ "0xea8e4eb5": contractErrors.NotAuthorized,
5079
+ "0x29c3b7ee": contractErrors.NotSelf,
5080
+ "0x584a7938": contractErrors.NotWhitelisted,
5081
+ "0xa8143fbc": contractErrors.NotCircleAdmin,
5082
+ // Circle / community management
5083
+ "0x430f13b3": contractErrors.InvalidName,
5084
+ "0xe7cbf75a": contractErrors.InvalidCommunityUrl,
5085
+ "0x3762bfee": contractErrors.InvalidAdminCommunityUrl,
5086
+ "0x201c1ffc": contractErrors.AdminAlreadyHasCircle,
5087
+ "0x6540a51d": contractErrors.CircleNameAlreadyTaken,
5088
+ "0xcadc6786": contractErrors.P2PStakeConfigNotSet,
5089
+ "0x78317f44": contractErrors.InsufficientP2PStake,
5090
+ "0x18eda032": contractErrors.P2PTokenNotSet,
5091
+ "0xdab11ea6": contractErrors.P2PUnstakeRequestPending,
5092
+ "0xeb1ce40b": contractErrors.NoP2PUnstakeRequest,
5093
+ "0xbf2d0ba1": contractErrors.P2PUnstakeCooldownNotPassed,
5094
+ "0x06b663af": contractErrors.SlashAmountExceedsStake,
5095
+ "0xff9b022c": contractErrors.CircleNotActive,
5096
+ "0x3d90c0a6": contractErrors.InvalidCircleId,
5097
+ "0xfb42a67d": contractErrors.CurrencyMismatch,
5098
+ "0xf2775265": contractErrors.CircleFull,
5099
+ "0x784b6c3c": contractErrors.CircleIdMismatch,
5100
+ "0xee240e49": contractErrors.DuplicateAccountName,
5101
+ "0x2ef13105": contractErrors.EmptyName,
5102
+ "0x1b5433c8": contractErrors.AccountBoundToAnotherCircle,
5103
+ "0x549e2555": contractErrors.ExitAmountExceededCircleBalance,
5104
+ "0x865b21e1": contractErrors.UndelegationAmountTooHigh,
5105
+ // Exchange / order lifecycle
5106
+ "0x4bbac5de": contractErrors.ExchangeNotOperational,
5107
+ "0x58db8ed6": contractErrors.OrderNotPlaced,
5108
+ "0x1e3b9629": contractErrors.OrderNotPaid,
5109
+ "0x181b1b2e": contractErrors.OrderStatusInvalid,
5110
+ "0xc56873ba": contractErrors.OrderExpired,
5111
+ "0x7f61b868": contractErrors.OrderAlreadyPaid,
5112
+ "0x03683687": contractErrors.OrderAlreadyCompleted,
5113
+ "0x688c176f": contractErrors.InvalidOrderType,
5114
+ "0x2e757a60": contractErrors.OrderTypeIncorrect,
5115
+ "0x6b1b90b4": contractErrors.OrderNotAccepted,
5116
+ "0x1775c43e": contractErrors.OrderNotAssigned,
5117
+ "0xf42e41a1": contractErrors.OrderAmountExceedsLimit,
5118
+ "0x93845d68": contractErrors.InvalidOrderAmount,
5119
+ "0x138b9d5a": contractErrors.InvalidOrderAmountToCoverFee,
5120
+ "0x5d706033": contractErrors.InvalidOrderId,
5121
+ "0xbb776720": contractErrors.OrderTooEarlyForReassignment,
5122
+ "0x20d5910f": contractErrors.OrderTooLateForReassignment,
5123
+ "0xccd87bf0": contractErrors.ReAssignmentNotRequired,
5124
+ "0xb20277f8": contractErrors.TipAlreadyGiven,
5125
+ "0xdf9f707c": contractErrors.CashbackTransferFailed,
5126
+ // Order limits
5127
+ "0xe595a7bf": contractErrors.DailyBuyOrderLimitExceeded,
5128
+ "0x675dbc86": contractErrors.MonthlyBuyOrderLimitExceeded,
5129
+ "0x64301cb8": contractErrors.SellOrderAmountLimitExceeded,
5130
+ "0x91da284f": contractErrors.BuyOrderAmountExceedsLimit,
5131
+ "0xb407b9ec": contractErrors.SellOrderAmountExceedsLimit,
5132
+ "0x4b29cf0a": contractErrors.BuyAmountExceedsUsdcLimit,
5133
+ "0xbba2edf9": contractErrors.SellAmountExceedsFiatLimit,
5134
+ "0x7e2ee654": contractErrors.DailyVolumeLimitExceeded,
5135
+ "0x49de1789": contractErrors.MonthlyVolumeLimitExceeded,
5136
+ "0xb14a1ff3": contractErrors.UserYearlyVolumeLimitExceeded,
5137
+ // Dispute
5138
+ "0x07a2454f": contractErrors.DisputeTimeNotReached,
5139
+ "0xb28c3e29": contractErrors.DisputeTimeExpired,
5140
+ "0x2a829f07": contractErrors.InvalidOrderStatusToRaiseDispute,
5141
+ "0x88d039ce": contractErrors.DisputeNotRaised,
5142
+ "0x3764a75c": contractErrors.CannotRaiseDisputeTwice,
5143
+ "0x866e9f89": contractErrors.DisputeAlreadySettled,
5144
+ "0x6131d13d": contractErrors.TransactionIdMismatch,
5145
+ "0x8ec051b8": contractErrors.AccountNumberMismatch,
5146
+ "0xf8bfad32": contractErrors.NotPaidBuyOrder,
5147
+ // Payment channels
5148
+ "0x552ff5ec": contractErrors.PaymentChannelNotFound,
5149
+ "0xfccd93cf": contractErrors.PaymentChannelNotActive,
5150
+ "0x6764f4d6": contractErrors.PaymentChannelNotApproved,
5151
+ "0xab284291": contractErrors.PaymentChannelNotRejected,
5152
+ "0x99c8ef4d": contractErrors.InvalidPaymentChannelId,
5153
+ "0x0569ab3e": contractErrors.DuplicatePaymentChannel,
5154
+ "0xff4f83ca": contractErrors.OldPaymentChannelNotFound,
5155
+ "0xb1198199": contractErrors.NewPaymentChannelNotFound,
5156
+ "0xc905b99a": contractErrors.SamePaymentChannel,
5157
+ "0xcedb41f1": contractErrors.OldPaymentChannelShouldBeInactive,
5158
+ "0x487add97": contractErrors.NewPaymentChannelShouldBeActive,
5159
+ "0x6d4c3f9e": contractErrors.OngoingOrderOnPaymentChannel,
5160
+ "0xc1654697": contractErrors.UpiAlreadySent,
5161
+ "0xaa60ec26": contractErrors.InvalidOrderUpi,
5162
+ "0x81c2b982": contractErrors.NoFiatLiquidity,
5163
+ // Merchant
5164
+ "0x5d04ff4c": contractErrors.NotEnoughEligibleMerchants,
5165
+ "0xa6af7ebe": contractErrors.MerchantNotRegistered,
5166
+ "0x7290a612": contractErrors.MerchantNotApproved,
5167
+ "0xf4a1e014": contractErrors.MerchantAlreadyRegistered,
5168
+ "0x8713aaba": contractErrors.MerchantAlreadyRejected,
5169
+ "0x9ae55bc7": contractErrors.MerchantBlacklisted,
5170
+ "0x0ee0b659": contractErrors.MerchantNotBlacklisted,
5171
+ "0x5f765689": contractErrors.MerchantAlreadyBlacklisted,
5172
+ "0x9c54e5a8": contractErrors.MerchantHasOngoingOrders,
5173
+ "0x70d753bd": contractErrors.MerchantNotFullfilledEligibilityThreshold,
5174
+ "0xc0b6c919": contractErrors.InvalidMerchant,
5175
+ // Staking / unstaking
5176
+ "0x3fd2347e": contractErrors.StakeAmountTooLow,
5177
+ "0x703cde0a": contractErrors.AdditionalStakeNotAllowed,
5178
+ "0xa9de99ae": contractErrors.UnstakeRequestPending,
5179
+ "0x0b7c70f3": contractErrors.UnstakeRequestNotPending,
5180
+ "0xe665491f": contractErrors.UnstakeAmountExceeded,
5181
+ "0x2d3087f9": contractErrors.ZeroUnstakeAmount,
5182
+ "0x1b1d7861": contractErrors.NoWithdrawableAmount,
5183
+ "0xcacf989a": contractErrors.NoStake,
5184
+ "0x21311aa3": contractErrors.NoStakers,
5185
+ "0xd06ff88e": contractErrors.InsufficientStakedAmount,
5186
+ "0x9ab7872d": contractErrors.CooldownNotPassed,
5187
+ "0x73380d99": contractErrors.ClaimableRewardsNotAvailable,
5188
+ // Delegation
5189
+ "0xec4b3ce6": contractErrors.ExitWouldBreachDelegationInvariant,
5190
+ "0x8f90a426": contractErrors.AggregateDelegationExceedsTotalStaked,
5191
+ "0x2cc11576": contractErrors.InsufficientMerchantRewards,
5192
+ // Migration
5193
+ "0x92aa7d0f": contractErrors.InvalidMigrationStatus,
5194
+ "0x7ff47425": contractErrors.MigrationRequestNotPending,
5195
+ "0x88ddec46": contractErrors.MigrationAlreadyRequested,
5196
+ // Token / currency
5197
+ "0xc991cbb1": contractErrors.TokenAlreadyExists,
5198
+ "0xcbdb7b30": contractErrors.TokenNotFound,
5199
+ "0x9f11a53f": contractErrors.TokenEmpty,
5200
+ "0x02a6fdd2": contractErrors.CurrencyNotSupported,
5201
+ "0xf5993428": contractErrors.InvalidCurrency,
5202
+ // USDC / transfer
5203
+ "0x149f9fca": contractErrors.UsdtTransferFailed,
5204
+ "0x47bfece5": contractErrors.UsdtTransferFailedWithErrorMessage,
5205
+ "0x279bbc0c": contractErrors.UsdtTransferFailedWithPanic,
5206
+ "0xfb8f41b2": contractErrors.InsufficientAllowance,
5207
+ // ZK Passport
5208
+ "0xfd8d4a6d": contractErrors.ZKPassportVerifierNotSet,
5209
+ "0xb87078f9": contractErrors.ZKPassportDomainEmpty,
5210
+ "0x5eadc4c2": contractErrors.ZKPassportScopeEmpty,
5211
+ "0x7642fe15": contractErrors.PassportAlreadyVerified,
5212
+ "0x1fa24b35": contractErrors.ZKPassportProofInvalid,
5213
+ "0x36bdb7b6": contractErrors.ZKPassportIdentifierAlreadyVerified,
5214
+ "0xd13a7934": contractErrors.ZKPassportInvalidScope,
5215
+ "0x69f5bfe7": contractErrors.ZKPassportUnexpectedSender,
5216
+ "0x0464115c": contractErrors.ZKPassportAgeBelowMinimum,
5217
+ "0x48183836": contractErrors.ZKPassportMinAgeTooHigh,
5218
+ // Chainlink / oracle
5219
+ "0x7f73f237": contractErrors.UnexpectedRequestId,
5220
+ "0xab948796": contractErrors.OnlyRouterCanFulfill,
5221
+ "0x61982c98": contractErrors.RequestFailed,
5222
+ "0xab66be18": contractErrors.SourceCodeMismatch,
5223
+ "0xff2826ef": contractErrors.ZeroMarketPrice,
5224
+ "0xbb6c216c": contractErrors.InvalidComputedPrices,
5225
+ "0x3a8fbef4": contractErrors.NotPriceUpdaterForCurrency,
5226
+ "0x3e2c36f2": contractErrors.ThresholdNotConfigured,
5227
+ "0x71c4efed": contractErrors.SlippageExceeded,
5228
+ // Reputation / verification
5229
+ "0x071ea33c": contractErrors.UserHasNoReputation,
5230
+ "0xd2e1e6e0": contractErrors.ZeroReputationPoints,
5231
+ "0x3c0ca622": contractErrors.NoReputation,
5232
+ "0x412dd2b1": contractErrors.InsufficientRP,
5233
+ "0x0f165e7b": contractErrors.NullifierAlreadyVerified,
5234
+ "0x439cc0cd": contractErrors.VerificationFailed,
5235
+ "0x2366073b": contractErrors.InvalidSocialPlatform,
5236
+ "0x2f850b6b": contractErrors.SocialAlreadyVerified,
5237
+ "0x466f52a8": contractErrors.YearFieldNotInProof,
5238
+ "0x4d460588": contractErrors.UserIdFieldNotInProof,
5239
+ "0xa18ea4e8": contractErrors.UserIdAlreadyVerified,
5240
+ "0x69470b13": contractErrors.UsernameAlreadyVerified,
5241
+ "0x8390b2dd": contractErrors.UsernameNotInProof,
5242
+ "0xef053cf4": contractErrors.LinkedInOnlyRpUpdates,
5243
+ "0x355b0709": contractErrors.FacebookOnlyRpUpdates,
5244
+ // Voting / referral
5245
+ "0x7aabdfe3": contractErrors.AlreadyReferred,
5246
+ "0x83463f4a": contractErrors.SelfReferralNotAllowed,
5247
+ "0x69f6994a": contractErrors.NotEligibleToRefer,
5248
+ "0x1b19ad97": contractErrors.MerchantMonthlyReferralLimitReached,
5249
+ "0x944a2241": contractErrors.NoRecommender,
5250
+ "0x0ece93a6": contractErrors.RecommendationAlreadyClaimed,
5251
+ "0x74785d0f": contractErrors.CannotVoteYourself,
5252
+ "0xc26d5f75": contractErrors.VotesPerEpochExceeded,
5253
+ "0x7c9a1cf9": contractErrors.AlreadyVoted,
5254
+ "0x403e7fa6": contractErrors.FunctionNotFound,
5255
+ // Campaign
5256
+ "0x7a551e38": contractErrors.CampaignNotActive,
5257
+ "0x668ca75d": contractErrors.InvalidManagerDetails,
5258
+ "0x2f950361": contractErrors.UnclaimedRewardsExist,
5259
+ "0x626b7c00": contractErrors.RewardAlreadyClaimed,
5260
+ "0x902ade67": contractErrors.OnlyNewUsersAllowed,
5261
+ "0x22a5e34b": contractErrors.ManagerNotFound,
5262
+ "0xa1610e37": contractErrors.ManagerInactive,
5263
+ "0x3fb087f4": contractErrors.NoRewards,
5264
+ "0x3eedee0f": contractErrors.InvalidCampaignId,
5265
+ "0x302c5138": contractErrors.CannotClaimRevenueForCurrentMonth,
5266
+ // Referral reward config
5267
+ "0x074a6991": contractErrors.RewardPercentageTooHigh,
5268
+ // Signature / nonce
5269
+ "0x1fb09b80": contractErrors.NonceAlreadyUsed,
5270
+ "0x2fdec18b": contractErrors.SignatureValidationFailed,
5271
+ // Misc
5272
+ "0xe6c4247b": contractErrors.InvalidAddress,
5273
+ "0x3eb17c88": contractErrors.InvalidBlockAmount,
5274
+ "0x2c5211c6": contractErrors.InvalidAmount,
5275
+ "0xb4fa3fb3": contractErrors.InvalidInput,
5276
+ "0x1117a646": contractErrors.InvalidStatusTransition,
5277
+ "0xa24a13a6": contractErrors.ArrayLengthMismatch,
5278
+ "0xebb6f34b": contractErrors.UserIsBlacklisted,
5279
+ "0xd92e233d": contractErrors.ZeroAddress,
5280
+ "0x8beb9d16": contractErrors.ReentrancyGuard,
5281
+ "0xbb1cb70b": contractErrors.BatchTooLarge,
5282
+ "0xd97cf1ba": contractErrors.UnderflowSubtraction,
5283
+ "0xc9b16952": contractErrors.TargetLongerThanData
5284
+ };
5285
+
5286
+ // src/contracts/order-flow/index.ts
5287
+ import { ResultAsync as ResultAsync7 } from "neverthrow";
5288
+
5289
+ // src/orders/internal/routing/errors.ts
5290
+ var OrderRoutingError = class extends SdkError {
5291
+ constructor(message, options) {
5292
+ super(message, options);
5293
+ this.name = "OrderRoutingError";
5294
+ }
5295
+ };
5296
+
5297
+ // src/orders/internal/routing/validation.ts
5298
+ import { z as z6 } from "zod";
5299
+ var ZodCircleScoreStateSchema = z6.object({
5300
+ activeMerchantsCount: z6.coerce.number()
5301
+ });
5302
+ var ZodCircleMetricsForRoutingSchema = z6.object({
5303
+ circleScore: z6.coerce.number(),
5304
+ circleStatus: z6.string(),
5305
+ scoreState: ZodCircleScoreStateSchema
5306
+ });
5307
+ var ZodCircleForRoutingSchema = z6.object({
5308
+ circleId: z6.string(),
5309
+ currency: z6.string(),
5310
+ metrics: ZodCircleMetricsForRoutingSchema
5311
+ });
5312
+ var ZodCirclesForRoutingResponseSchema = z6.object({
5313
+ circles: z6.array(ZodCircleForRoutingSchema)
5314
+ });
5315
+ var ZodCheckCircleEligibilityParamsSchema = z6.object({
5316
+ circleId: z6.bigint(),
5317
+ currency: z6.string(),
5318
+ user: ZodAddressSchema,
5319
+ usdtAmount: z6.bigint(),
5320
+ fiatAmount: z6.bigint(),
5321
+ orderType: z6.bigint(),
5322
+ preferredPCConfigId: z6.bigint()
5323
+ });
5324
+ var ZodSelectCircleParamsSchema = z6.object({
5325
+ currency: z6.string().min(1),
5326
+ user: ZodAddressSchema,
5327
+ usdtAmount: z6.bigint(),
5328
+ fiatAmount: z6.bigint(),
5329
+ orderType: z6.bigint(),
5330
+ preferredPCConfigId: z6.bigint()
5331
+ });
5332
+
5333
+ // src/contracts/order-flow/index.ts
5334
+ function checkCircleEligibility(publicClient, contractAddress, params, logger = noopLogger) {
5335
+ return validate(
5336
+ ZodCheckCircleEligibilityParamsSchema,
5337
+ params,
5338
+ (message, cause, d) => new OrderRoutingError(message, { code: "VALIDATION_ERROR", cause, context: { data: d } })
5339
+ ).asyncAndThen((validated) => {
5340
+ logger.debug("checking on-chain eligibility", {
5341
+ circleId: String(validated.circleId),
5342
+ contractAddress
5343
+ });
5344
+ return ResultAsync7.fromPromise(
5345
+ publicClient.readContract({
5346
+ address: contractAddress,
5347
+ abi: ABIS.FACETS.ORDER_FLOW,
5348
+ functionName: "getAssignableMerchantsFromCircle",
5349
+ args: [
5350
+ validated.circleId,
5351
+ 1n,
5352
+ validated.currency,
5353
+ validated.user,
5354
+ validated.usdtAmount,
5355
+ validated.fiatAmount,
5356
+ validated.orderType,
5357
+ validated.preferredPCConfigId
5358
+ ]
5359
+ }),
5360
+ (error) => new OrderRoutingError("Eligibility check failed", {
5361
+ code: "CONTRACT_READ_ERROR",
5362
+ cause: error,
5363
+ context: { circleId: String(params.circleId) }
5364
+ })
5365
+ );
5366
+ }).map((merchants) => {
5367
+ const arr = merchants;
5368
+ const eligible = arr.length >= 1;
5369
+ logger.debug("eligibility check result", {
5370
+ circleId: String(params.circleId),
5371
+ assignableMerchants: arr.length,
5372
+ eligible
5373
+ });
5374
+ return eligible;
5375
+ });
5376
+ }
5377
+
5378
+ // src/contracts/p2p-config/index.ts
5379
+ import { ResultAsync as ResultAsync8 } from "neverthrow";
5380
+ import { stringToHex as stringToHex4 } from "viem";
5381
+
5382
+ // src/prices/errors.ts
5383
+ var PricesError = class extends SdkError {
5384
+ constructor(message, options) {
5385
+ super(message, options);
5386
+ this.name = "PricesError";
5387
+ }
5388
+ };
5389
+
5390
+ // src/prices/validation.ts
5391
+ import { z as z7 } from "zod";
5392
+ var ZodCurrencyScopedParamsSchema = z7.object({
5393
+ currency: ZodCurrencySchema
5394
+ });
5395
+
5396
+ // src/contracts/p2p-config/index.ts
5397
+ function getPriceConfig(publicClient, diamondAddress, params) {
5398
+ return validate(
5399
+ ZodCurrencyScopedParamsSchema,
5400
+ params,
5401
+ (message, cause, data) => new PricesError(message, {
5402
+ code: "VALIDATION_ERROR",
5403
+ cause,
5404
+ context: { params: data }
5405
+ })
5406
+ ).asyncAndThen(
5407
+ (validated) => ResultAsync8.fromPromise(
5408
+ publicClient.readContract({
5409
+ address: diamondAddress,
5410
+ abi: ABIS.FACETS.CONFIG,
5411
+ functionName: "getPriceConfig",
5412
+ args: [stringToHex4(validated.currency, { size: 32 })]
5413
+ }),
5414
+ (error) => new PricesError("Failed to read price config", {
5415
+ code: "CONTRACT_READ_ERROR",
5416
+ cause: error,
5417
+ context: { currency: validated.currency, diamondAddress }
5418
+ })
5419
+ )
5420
+ );
5421
+ }
5422
+ function getReputationPerUsdcLimit(publicClient, diamondAddress, params) {
5423
+ return validate(
5424
+ ZodCurrencyScopedParamsSchema,
5425
+ params,
5426
+ (message, cause, data) => new PricesError(message, {
5427
+ code: "VALIDATION_ERROR",
5428
+ cause,
5429
+ context: { params: data }
5430
+ })
5431
+ ).asyncAndThen(
5432
+ (validated) => ResultAsync8.fromPromise(
5433
+ publicClient.readContract({
5434
+ address: diamondAddress,
5435
+ abi: ABIS.DIAMOND,
5436
+ functionName: "getRpPerUsdtLimitRational",
5437
+ args: [stringToHex4(validated.currency, { size: 32 })]
5438
+ }),
5439
+ (error) => new PricesError("Failed to read reputation-per-USDC limit", {
5440
+ code: "CONTRACT_READ_ERROR",
5441
+ cause: error,
5442
+ context: { currency: validated.currency, diamondAddress }
5443
+ })
5444
+ ).map(([numerator, denominator]) => ({
5445
+ numerator,
5446
+ denominator,
5447
+ multiplier: numerator > 0n ? Number(denominator) / Number(numerator) : 0
5448
+ }))
5449
+ );
5450
+ }
5451
+
5452
+ // src/contracts/reputation-manager/writes.ts
5453
+ import { Result as Result2 } from "neverthrow";
5454
+ import { encodeFunctionData as encodeFunctionData7 } from "viem";
5455
+
5456
+ // src/zkkyc/errors.ts
5457
+ var ZkkycError = class extends SdkError {
5458
+ constructor(message, options) {
5459
+ super(message, options);
5460
+ this.name = "ZkkycError";
5461
+ }
5462
+ };
5463
+
5464
+ // src/zkkyc/validation.ts
5465
+ import { z as z8 } from "zod";
5466
+ var ZodAnonAadharProofParamsSchema = z8.object({
5467
+ nullifierSeed: z8.bigint(),
5468
+ nullifier: z8.bigint(),
5469
+ timestamp: z8.bigint(),
5470
+ signal: z8.bigint(),
5471
+ revealArray: z8.tuple([z8.bigint(), z8.bigint(), z8.bigint(), z8.bigint()]),
5472
+ packedGroth16Proof: z8.tuple([
5473
+ z8.bigint(),
5474
+ z8.bigint(),
5475
+ z8.bigint(),
5476
+ z8.bigint(),
5477
+ z8.bigint(),
5478
+ z8.bigint(),
5479
+ z8.bigint(),
5480
+ z8.bigint()
5481
+ ])
5482
+ });
5483
+ var ZodSocialVerifyParamsSchema = z8.object({
5484
+ _socialName: z8.string(),
5485
+ proofs: z8.array(
5486
+ z8.object({
5487
+ claimInfo: z8.object({
5488
+ provider: z8.string(),
5489
+ parameters: z8.string(),
5490
+ context: z8.string()
5491
+ }),
5492
+ signedClaim: z8.object({
5493
+ claim: z8.object({
5494
+ identifier: z8.string(),
5495
+ owner: ZodAddressSchema,
5496
+ timestampS: z8.number(),
5497
+ epoch: z8.number()
5498
+ }),
5499
+ signatures: z8.array(z8.string())
5500
+ })
5501
+ })
5502
+ )
5503
+ });
5504
+ var ZodSolidityVerifierParametersSchema = z8.object({
5505
+ version: z8.string().refine((val) => val.startsWith("0x"), {
5506
+ message: "Version must be a hex string"
5507
+ }),
5508
+ proofVerificationData: z8.object({
5509
+ vkeyHash: z8.string().refine((val) => /^0x[a-fA-F0-9]{64}$/.test(val), {
5510
+ message: "Invalid bytes32 hex string"
5511
+ }),
5512
+ proof: z8.string().refine((val) => val.startsWith("0x"), {
5513
+ message: "Proof must be a hex string"
5514
+ }),
5515
+ publicInputs: z8.array(
5516
+ z8.string().refine((val) => /^0x[a-fA-F0-9]{64}$/.test(val), {
5517
+ message: "Each public input must be a valid bytes32 hex string"
5518
+ })
5519
+ )
5520
+ }),
5521
+ committedInputs: z8.string().refine((val) => val.startsWith("0x"), {
5522
+ message: "Committed inputs must be a hex string"
5523
+ }),
5524
+ serviceConfig: z8.object({
5525
+ validityPeriodInSeconds: z8.number().int().nonnegative(),
5526
+ domain: z8.string(),
5527
+ scope: z8.string(),
5528
+ devMode: z8.boolean()
5529
+ })
5530
+ });
5531
+ var ZodZkPassportRegisterParamsSchema = z8.object({
5532
+ params: ZodSolidityVerifierParametersSchema,
5533
+ isIDCard: z8.boolean()
5534
+ });
5535
+
5536
+ // src/contracts/reputation-manager/writes.ts
5537
+ function prepareSocialVerify(reputationManagerAddress, params) {
5538
+ return validate(
5539
+ ZodSocialVerifyParamsSchema,
5540
+ params,
5541
+ (message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
5542
+ ).andThen(
5543
+ (validated) => Result2.fromThrowable(
5544
+ () => ({
5545
+ to: reputationManagerAddress,
5546
+ data: encodeFunctionData7({
5547
+ abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
5548
+ functionName: "socialVerify",
5549
+ args: [
5550
+ validated._socialName,
5551
+ validated.proofs.map((proof) => ({
5552
+ ...proof,
5553
+ signedClaim: {
5554
+ ...proof.signedClaim,
5555
+ claim: {
5556
+ ...proof.signedClaim.claim,
5557
+ identifier: proof.signedClaim.claim.identifier
5558
+ },
5559
+ signatures: proof.signedClaim.signatures
5560
+ }
5561
+ }))
5562
+ ]
5563
+ })
5564
+ }),
5565
+ (error) => new ZkkycError("Failed to encode socialVerify", {
5566
+ code: "ENCODE_ERROR",
5567
+ cause: error
5568
+ })
5569
+ )()
5570
+ );
5571
+ }
5572
+ function prepareSubmitAnonAadharProof(reputationManagerAddress, params) {
5573
+ return validate(
5574
+ ZodAnonAadharProofParamsSchema,
5575
+ params,
5576
+ (message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
5577
+ ).andThen(
5578
+ (validated) => Result2.fromThrowable(
5579
+ () => ({
5580
+ to: reputationManagerAddress,
5581
+ data: encodeFunctionData7({
5582
+ abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
5583
+ functionName: "submitAnonAadharProof",
5584
+ args: [
5585
+ validated.nullifierSeed,
5586
+ validated.nullifier,
5587
+ validated.timestamp,
5588
+ validated.signal,
5589
+ validated.revealArray,
5590
+ validated.packedGroth16Proof
5591
+ ]
5592
+ })
5593
+ }),
5594
+ (error) => new ZkkycError("Failed to encode submitAnonAadharProof", {
5595
+ code: "ENCODE_ERROR",
5596
+ cause: error
5597
+ })
5598
+ )()
5599
+ );
5600
+ }
5601
+ function prepareZkPassportRegister(reputationManagerAddress, params) {
5602
+ return validate(
5603
+ ZodZkPassportRegisterParamsSchema,
5604
+ params,
5605
+ (message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
5606
+ ).andThen(
5607
+ (validated) => Result2.fromThrowable(
5608
+ () => {
5609
+ const { proofVerificationData, serviceConfig, committedInputs, version } = validated.params;
5610
+ const proofVerificationParams = {
5611
+ version,
5612
+ proofVerificationData: {
5613
+ vkeyHash: proofVerificationData.vkeyHash,
5614
+ proof: proofVerificationData.proof,
5615
+ publicInputs: proofVerificationData.publicInputs
5616
+ },
5617
+ committedInputs,
5618
+ serviceConfig: {
5619
+ validityPeriodInSeconds: BigInt(serviceConfig.validityPeriodInSeconds),
5620
+ domain: serviceConfig.domain,
5621
+ scope: serviceConfig.scope,
5622
+ devMode: serviceConfig.devMode
5623
+ }
5624
+ };
5625
+ return {
5626
+ to: reputationManagerAddress,
5627
+ data: encodeFunctionData7({
5628
+ abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
5629
+ functionName: "zkPassportRegister",
5630
+ args: [proofVerificationParams, validated.isIDCard]
5631
+ })
5632
+ };
5633
+ },
5634
+ (error) => new ZkkycError("Failed to encode zkPassportRegister", {
5635
+ code: "ENCODE_ERROR",
5636
+ cause: error
5637
+ })
5638
+ )()
5639
+ );
5640
+ }
5641
+
5642
+ // src/contracts/tx-limits/index.ts
5643
+ import { ResultAsync as ResultAsync9 } from "neverthrow";
5644
+ import { formatUnits, stringToHex as stringToHex5 } from "viem";
5645
+
5646
+ // src/profile/errors.ts
5647
+ var ProfileError = class extends SdkError {
5648
+ constructor(message, options) {
5649
+ super(message, options);
5650
+ this.name = "ProfileError";
5651
+ }
5652
+ };
5653
+
5654
+ // src/profile/validation.ts
5655
+ import { z as z9 } from "zod";
5656
+ var ZodUsdcBalanceParamsSchema = z9.object({
5657
+ address: ZodAddressSchema
5658
+ });
5659
+ var ZodUsdcAllowanceParamsSchema = z9.object({
5660
+ owner: ZodAddressSchema
5661
+ });
5662
+ var ZodGetBalancesParamsSchema = z9.object({
5663
+ address: ZodAddressSchema,
5664
+ currency: ZodCurrencySchema
5665
+ });
5666
+ var ZodTxLimitsParamsSchema = z9.object({
5667
+ address: ZodAddressSchema,
5668
+ currency: ZodCurrencySchema
5669
+ });
5670
+
5671
+ // src/contracts/tx-limits/index.ts
5672
+ function getTxLimits(publicClient, diamondAddress, params) {
5673
+ return validate(
5674
+ ZodTxLimitsParamsSchema,
5675
+ params,
5676
+ (message, cause, data) => new ProfileError(message, {
5677
+ code: "VALIDATION_ERROR",
5678
+ cause,
5679
+ context: { params: data }
5680
+ })
5681
+ ).asyncAndThen(
5682
+ (validated) => ResultAsync9.fromPromise(
5683
+ publicClient.readContract({
5684
+ address: diamondAddress,
5685
+ abi: ABIS.FACETS.ORDER_FLOW,
5686
+ functionName: "userTxLimit",
5687
+ args: [validated.address, stringToHex5(validated.currency, { size: 32 })]
5688
+ }),
5689
+ (error) => new ProfileError("Failed to read tx limits", {
5690
+ code: "CONTRACT_READ_ERROR",
5691
+ cause: error,
5692
+ context: { address: validated.address, currency: validated.currency, diamondAddress }
5693
+ })
5694
+ ).map(([buyLimit, sellLimit]) => ({
5695
+ buyLimit: Number(formatUnits(buyLimit, 6)),
5696
+ sellLimit: Number(formatUnits(sellLimit, 6))
5697
+ }))
5698
+ );
5699
+ }
5700
+
5701
+ // src/contracts/usdc/index.ts
5702
+ import { ResultAsync as ResultAsync10 } from "neverthrow";
5703
+ import { erc20Abi as erc20Abi3 } from "viem";
5704
+ function getUsdcBalance(publicClient, usdcAddress, params) {
5705
+ return validate(
5706
+ ZodUsdcBalanceParamsSchema,
5707
+ params,
5708
+ (message, cause, data) => new ProfileError(message, {
5709
+ code: "VALIDATION_ERROR",
5710
+ cause,
5711
+ context: { params: data }
5712
+ })
5713
+ ).asyncAndThen(
5714
+ (validated) => ResultAsync10.fromPromise(
5715
+ publicClient.readContract({
5716
+ address: usdcAddress,
5717
+ abi: ABIS.EXTERNAL.USDC,
5718
+ functionName: "balanceOf",
5719
+ args: [validated.address]
5720
+ }),
5721
+ (error) => new ProfileError("Failed to read USDC balance", {
5722
+ code: "CONTRACT_READ_ERROR",
5723
+ cause: error,
5724
+ context: { address: validated.address, usdcAddress }
5725
+ })
5726
+ )
5727
+ );
5728
+ }
5729
+ function getUsdcAllowance(publicClient, usdcAddress, diamondAddress, params) {
5730
+ return validate(
5731
+ ZodUsdcAllowanceParamsSchema,
5732
+ params,
5733
+ (message, cause, data) => new ProfileError(message, {
5734
+ code: "VALIDATION_ERROR",
5735
+ cause,
5736
+ context: { params: data }
5737
+ })
5738
+ ).asyncAndThen(
5739
+ (validated) => ResultAsync10.fromPromise(
5740
+ publicClient.readContract({
5741
+ address: usdcAddress,
5742
+ abi: erc20Abi3,
5743
+ functionName: "allowance",
5744
+ args: [validated.owner, diamondAddress]
5745
+ }),
5746
+ (error) => new ProfileError("Failed to read USDC allowance", {
5747
+ code: "CONTRACT_READ_ERROR",
5748
+ cause: error,
5749
+ context: { owner: validated.owner, usdcAddress, diamondAddress }
5750
+ })
5751
+ )
5752
+ );
5753
+ }
5754
+
5755
+ // src/orders/internal/routing/routing.ts
5756
+ import { errAsync as errAsync3, okAsync as okAsync3 } from "neverthrow";
5757
+ var EPSILON = 0.25;
5758
+ var RECOVERY_SCALE = 0.3;
5759
+ var BOOTSTRAP_MAX_WEIGHT = 25;
5760
+ var MAX_VALIDATION_ATTEMPTS = 3;
5761
+ function circleWeight(c) {
5762
+ const score = c.metrics.circleScore;
5763
+ if (c.metrics.circleStatus === "paused") {
5764
+ return score * RECOVERY_SCALE;
5765
+ }
5766
+ if (c.metrics.circleStatus === "bootstrap") {
5767
+ return Math.min(score, BOOTSTRAP_MAX_WEIGHT);
5768
+ }
5769
+ return score;
5770
+ }
5771
+ function filterEligibleCircles(circles, orderCurrency) {
5772
+ return circles.filter((c) => c.currency.toLowerCase() === orderCurrency.toLowerCase());
5773
+ }
5774
+ function weightedRandomChoice(arr, weights) {
5775
+ const totalWeight = weights.reduce((sum, w) => sum + w, 0);
5776
+ if (totalWeight === 0) {
5777
+ return arr[Math.floor(Math.random() * arr.length)];
5778
+ }
5779
+ let rand = Math.random() * totalWeight;
5780
+ for (let i = 0; i < arr.length; i++) {
5781
+ rand -= weights[i];
5782
+ if (rand <= 0) {
5783
+ return arr[i];
5784
+ }
5785
+ }
5786
+ return arr[arr.length - 1];
5787
+ }
5788
+ function selectCircle(eligible) {
5789
+ if (eligible.length === 0) {
5790
+ return null;
5791
+ }
5792
+ const activeCircles = eligible.filter((c) => c.metrics.circleStatus === "active");
5793
+ const isExplore = Math.random() < EPSILON;
5794
+ if (isExplore) {
5795
+ const weights2 = eligible.map(circleWeight);
5796
+ return weightedRandomChoice(eligible, weights2);
5797
+ }
5798
+ if (activeCircles.length === 0) {
5799
+ const weights2 = eligible.map(circleWeight);
5800
+ return weightedRandomChoice(eligible, weights2);
5801
+ }
5802
+ const weights = activeCircles.map((c) => c.metrics.circleScore);
5803
+ return weightedRandomChoice(activeCircles, weights);
5804
+ }
5805
+ function selectCircleForOrderAsync(circles, orderCurrency, validateCircle, logger = noopLogger) {
5806
+ const eligible = filterEligibleCircles(circles, orderCurrency);
5807
+ let remaining = [...eligible];
5808
+ logger.debug("filtering eligible circles", {
5809
+ total: circles.length,
5810
+ eligible: eligible.length,
5811
+ currency: orderCurrency,
5812
+ circles: eligible
5813
+ });
5814
+ if (eligible.length === 0) {
5815
+ logger.warn("no eligible circles found for currency", { currency: orderCurrency });
5816
+ }
5817
+ function attempt(attemptsLeft) {
5818
+ if (attemptsLeft <= 0 || remaining.length === 0) {
5819
+ logger.warn("exhausted all attempts or circles", {
5820
+ attemptsLeft,
5821
+ remainingCircles: remaining.length
5822
+ });
5823
+ return errAsync3(
5824
+ new OrderRoutingError("No eligible circles found", {
5825
+ code: "NO_ELIGIBLE_CIRCLES"
5826
+ })
5827
+ );
5828
+ }
5829
+ const selected = selectCircle(remaining);
5830
+ if (!selected) {
5831
+ return errAsync3(
5832
+ new OrderRoutingError("No eligible circles found", {
5833
+ code: "NO_ELIGIBLE_CIRCLES"
5834
+ })
5835
+ );
5836
+ }
5837
+ const circleId = BigInt(selected.circleId);
5838
+ logger.debug("selected circle, validating on-chain", {
5839
+ circleId: String(circleId),
5840
+ status: selected.metrics.circleStatus,
5841
+ score: selected.metrics.circleScore,
5842
+ attemptsLeft
5843
+ });
5844
+ return validateCircle(circleId).orElse((error) => {
5845
+ logger.warn("validation errored, treating as ineligible", {
5846
+ circleId: String(circleId),
5847
+ error: String(error)
5848
+ });
5849
+ return okAsync3(false);
5850
+ }).andThen((isValid) => {
5851
+ if (isValid) {
5852
+ logger.info("circle validated successfully", { circleId: String(circleId) });
5853
+ return okAsync3(circleId);
5854
+ }
5855
+ logger.debug("circle failed validation, retrying", {
5856
+ circleId: String(circleId),
5857
+ remainingCircles: remaining.length - 1
5858
+ });
5859
+ remaining = remaining.filter((c) => c.circleId !== selected.circleId);
5860
+ return attempt(attemptsLeft - 1);
5861
+ });
5862
+ }
5863
+ return attempt(MAX_VALIDATION_ATTEMPTS);
5864
+ }
5865
+
5866
+ // src/orders/internal/routing/subgraph/queries.ts
5867
+ var CIRCLES_FOR_ROUTING_QUERY = (
5868
+ /* GraphQL */
5869
+ `
5870
+ query CirclesForRouting($currency: Bytes!) {
5871
+ circles(
5872
+ first: 1000
5873
+ where: {
5874
+ currency: $currency
5875
+ metrics_: {
5876
+ circleStatus_in: ["active", "bootstrap", "paused"]
5877
+ }
5878
+ }
5879
+ ) {
5880
+ circleId
5881
+ currency
5882
+ metrics {
5883
+ circleScore
5884
+ circleStatus
5885
+ scoreState {
5886
+ activeMerchantsCount
5887
+ }
5888
+ }
5889
+ }
5890
+ }
5891
+ `
5892
+ );
5893
+
5894
+ // src/orders/internal/routing/subgraph/index.ts
5895
+ function getCirclesForRouting(subgraphUrl, currency, logger = noopLogger) {
5896
+ logger.debug("fetching circles from subgraph", { subgraphUrl, currency });
5897
+ return querySubgraph(subgraphUrl, {
5898
+ query: CIRCLES_FOR_ROUTING_QUERY,
5899
+ variables: { currency }
5900
+ }).mapErr(
5901
+ (e) => new OrderRoutingError(e.message, {
5902
+ code: "SUBGRAPH_ERROR",
5903
+ cause: e.cause ?? e,
5904
+ context: e.context
5905
+ })
5906
+ ).andThen(
5907
+ (data) => validate(
5908
+ ZodCirclesForRoutingResponseSchema,
5909
+ data,
5910
+ (message, cause, d) => new OrderRoutingError(message, { code: "VALIDATION_ERROR", cause, context: { data: d } })
5911
+ ).map((validated) => {
5912
+ const circles = validated.circles.filter(
5913
+ (item) => Number(item.metrics.scoreState.activeMerchantsCount) > 0
5914
+ );
5915
+ logger.info("fetched circles from subgraph", {
5916
+ total: validated.circles.length,
5917
+ withActiveMerchants: circles.length,
5918
+ circles
5919
+ });
5920
+ return circles;
5921
+ })
5922
+ );
4337
5923
  }
4338
- async function encryptWithPublicKey(publicKey, message) {
4339
- const pubKeyBytes = hexToBytes3(`04${publicKey}`);
4340
- const ephemPrivKey = randomBytes(32);
4341
- const ephemPubKey = secp256k1.getPublicKey(ephemPrivKey, false);
4342
- const sharedPoint = secp256k1.getSharedSecret(ephemPrivKey, pubKeyBytes, true);
4343
- const sharedSecret = sharedPoint.slice(1);
4344
- const { encKey, macKey } = deriveKeys(sharedSecret);
4345
- const iv = randomBytes(16);
4346
- const plaintext = new TextEncoder().encode(message);
4347
- const cipher = cbc(encKey, iv);
4348
- const ciphertext = cipher.encrypt(plaintext);
4349
- const macData = concatBytes2(iv, ephemPubKey, ciphertext);
4350
- const mac = hmac(sha2562, macKey, macData);
5924
+
5925
+ // src/orders/internal/routing/client.ts
5926
+ function createOrderRouter(config) {
5927
+ const { subgraphUrl, publicClient, contractAddress } = config;
5928
+ const logger = config.logger ?? noopLogger;
4351
5929
  return {
4352
- iv: bytesToHex2(iv),
4353
- ephemPublicKey: bytesToHex2(ephemPubKey),
4354
- ciphertext: bytesToHex2(ciphertext),
4355
- mac: bytesToHex2(mac)
5930
+ selectCircle(params) {
5931
+ const currencyHex = stringToHex6(params.currency, { size: 32 });
5932
+ logger.info("selectCircle started", {
5933
+ currency: params.currency,
5934
+ user: params.user,
5935
+ orderType: String(params.orderType)
5936
+ });
5937
+ return getCirclesForRouting(subgraphUrl, currencyHex, logger).andThen(
5938
+ (circles) => selectCircleForOrderAsync(
5939
+ circles,
5940
+ currencyHex,
5941
+ (circleId) => checkCircleEligibility(
5942
+ publicClient,
5943
+ contractAddress,
5944
+ {
5945
+ circleId,
5946
+ currency: currencyHex,
5947
+ user: params.user,
5948
+ usdtAmount: params.usdtAmount,
5949
+ fiatAmount: params.fiatAmount,
5950
+ orderType: params.orderType,
5951
+ preferredPCConfigId: params.preferredPCConfigId
5952
+ },
5953
+ logger
5954
+ ),
5955
+ logger
5956
+ )
5957
+ );
5958
+ }
4356
5959
  };
4357
5960
  }
4358
- function cipherStringify(encrypted) {
4359
- const ephemPubKeyBytes = hexToBytes3(encrypted.ephemPublicKey);
4360
- const compressed = secp256k1.ProjectivePoint.fromHex(ephemPubKeyBytes).toRawBytes(true);
4361
- const iv = hexToBytes3(encrypted.iv);
4362
- const mac = hexToBytes3(encrypted.mac);
4363
- const ciphertext = hexToBytes3(encrypted.ciphertext);
4364
- return bytesToHex2(concatBytes2(iv, compressed, mac, ciphertext));
4365
- }
4366
5961
 
4367
- // src/payload/errors.ts
4368
- var PayloadError = class extends SdkError {
4369
- constructor(message, options) {
4370
- super(message, options);
4371
- this.name = "PayloadError";
4372
- }
5962
+ // src/orders/normalize.ts
5963
+ import { err as err4, ok as ok5, Result as Result3 } from "neverthrow";
5964
+ import { hexToString, isAddressEqual, zeroAddress } from "viem";
5965
+ var ORDER_TYPE_MAP = {
5966
+ [ORDER_TYPE.BUY]: "buy",
5967
+ [ORDER_TYPE.SELL]: "sell",
5968
+ [ORDER_TYPE.PAY]: "pay"
4373
5969
  };
4374
-
4375
- // src/payload/relay-identity.ts
4376
- import { ok as ok3 } from "neverthrow";
4377
- import { isAddress as isAddress2, isHex } from "viem";
4378
- import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
4379
- import { z as z6 } from "zod";
4380
- var ZodRelayIdentitySchema = z6.object({
4381
- address: z6.string().refine(isAddress2, { message: "Invalid relay identity address" }),
4382
- publicKey: z6.string().refine((val) => isHex(`0x${val}`), {
4383
- message: "Invalid relay identity public key"
4384
- }),
4385
- privateKey: z6.string().refine(isHex, { message: "Invalid relay identity private key" })
4386
- });
4387
- var STORAGE_KEY = "@P2PME:RELAY_IDENTITY";
4388
- function createRelayIdentity() {
4389
- const privateKey = generatePrivateKey();
4390
- const account = privateKeyToAccount(privateKey);
4391
- const rawPubKey = account.publicKey;
4392
- const publicKey = rawPubKey.slice(4);
4393
- const identity = {
4394
- address: account.address,
4395
- publicKey,
4396
- privateKey
4397
- };
4398
- localStorage.setItem(STORAGE_KEY, JSON.stringify(identity));
4399
- return identity;
5970
+ var ORDER_STATUS_MAP = {
5971
+ [ORDER_STATUS.PLACED]: "placed",
5972
+ [ORDER_STATUS.ACCEPTED]: "accepted",
5973
+ [ORDER_STATUS.PAID]: "paid",
5974
+ [ORDER_STATUS.COMPLETED]: "completed",
5975
+ [ORDER_STATUS.CANCELLED]: "cancelled"
5976
+ };
5977
+ var DISPUTE_STATUS_MAP = {
5978
+ [DISPUTE_STATUS.NONE]: "none",
5979
+ [DISPUTE_STATUS.OPEN]: "open",
5980
+ [DISPUTE_STATUS.RESOLVED]: "resolved"
5981
+ };
5982
+ function malformed(field, value, context) {
5983
+ return new OrdersError(`Unknown ${field}: ${String(value)}`, {
5984
+ code: "MALFORMED_ORDER",
5985
+ context: { field, value, ...context }
5986
+ });
4400
5987
  }
4401
- function getRelayIdentity() {
4402
- const data = localStorage.getItem(STORAGE_KEY);
4403
- if (!data) {
4404
- return ok3(createRelayIdentity());
4405
- }
4406
- let parsed;
4407
- try {
4408
- parsed = JSON.parse(data);
4409
- } catch {
4410
- return ok3(createRelayIdentity());
4411
- }
4412
- const result = validate(
4413
- ZodRelayIdentitySchema,
4414
- parsed,
4415
- (message, cause, d) => new PayloadError(message, { code: "VALIDATION_ERROR", cause, context: { data: d } })
4416
- );
4417
- if (result.isErr()) {
4418
- return ok3(createRelayIdentity());
4419
- }
4420
- return result;
5988
+ function mapOrderType(v, ctx) {
5989
+ const t = ORDER_TYPE_MAP[v];
5990
+ return t ? ok5(t) : err4(malformed("orderType", v, ctx));
5991
+ }
5992
+ function mapOrderStatus(v, ctx) {
5993
+ const s = ORDER_STATUS_MAP[v];
5994
+ return s ? ok5(s) : err4(malformed("status", v, ctx));
5995
+ }
5996
+ function mapDisputeStatus(v, ctx) {
5997
+ const s = DISPUTE_STATUS_MAP[v];
5998
+ return s ? ok5(s) : err4(malformed("disputeStatus", v, ctx));
5999
+ }
6000
+ function decodeCurrency(hex) {
6001
+ return hexToString(hex, { size: 32 }).replaceAll("\0", "");
6002
+ }
6003
+ function normalizeContractOrder(raw, details) {
6004
+ if (raw.id === 0n && isAddressEqual(raw.user, zeroAddress)) return ok5(null);
6005
+ const ctx = { orderId: raw.id.toString() };
6006
+ return Result3.combine([
6007
+ mapOrderType(raw.orderType, ctx),
6008
+ mapOrderStatus(raw.status, ctx),
6009
+ mapDisputeStatus(raw.disputeInfo.status, ctx)
6010
+ ]).map(([type, status, disputeStatus]) => ({
6011
+ orderId: raw.id,
6012
+ type,
6013
+ status,
6014
+ usdcAmount: raw.amount,
6015
+ fiatAmount: raw.fiatAmount,
6016
+ actualUsdcAmount: details.actualUsdtAmount,
6017
+ actualFiatAmount: details.actualFiatAmount,
6018
+ currency: decodeCurrency(raw.currency),
6019
+ user: raw.user,
6020
+ recipient: raw.recipientAddr,
6021
+ acceptedMerchant: raw.acceptedMerchant,
6022
+ placedAt: raw.placedTimestamp,
6023
+ acceptedAt: details.acceptedTimestamp,
6024
+ paidAt: details.paidTimestamp,
6025
+ completedAt: raw.completedTimestamp,
6026
+ circleId: raw.circleId,
6027
+ fixedFeePaid: details.fixedFeePaid,
6028
+ tipsPaid: details.tipsPaid,
6029
+ disputeStatus,
6030
+ encUpi: raw.encUpi,
6031
+ encMerchantUpi: raw.encMerchantUpi,
6032
+ pubkey: raw.pubkey
6033
+ }));
4421
6034
  }
4422
-
4423
- // src/payload/crypto.ts
4424
- function encryptPaymentAddress(paymentAddress, encryptionPublicKey) {
4425
- return safeTry(async function* () {
4426
- const relayIdentity = yield* getRelayIdentity().mapErr(
4427
- (e) => new PayloadError(`Relay identity error: ${e.message}`, {
4428
- code: "ENCRYPTION_ERROR",
4429
- cause: e
4430
- })
4431
- );
4432
- const messageHash = keccak256(stringToHex4(paymentAddress));
4433
- const signResult = yield* ResultAsync7.fromPromise(
4434
- sign({ hash: messageHash, privateKey: relayIdentity.privateKey }),
4435
- (error) => new PayloadError(
4436
- `Signing error: ${error instanceof Error ? error.message : "Unknown error"}`,
4437
- { code: "ENCRYPTION_ERROR", cause: error }
4438
- )
4439
- );
4440
- const signature = serializeSignature(signResult);
4441
- const payload = { message: paymentAddress, signature };
4442
- const encrypted = yield* ResultAsync7.fromPromise(
4443
- encryptWithPublicKey(encryptionPublicKey, JSON.stringify(payload)),
4444
- (error) => new PayloadError(
4445
- `Encryption error: ${error instanceof Error ? error.message : "Unknown error"}`,
4446
- { code: "ENCRYPTION_ERROR", cause: error }
4447
- )
4448
- );
4449
- const safeCipherStringify = Result2.fromThrowable(
4450
- (encryptedData) => cipherStringify(encryptedData),
4451
- (error) => new PayloadError(
4452
- `Stringify error: ${error instanceof Error ? error.message : "Unknown error"}`,
4453
- { code: "ENCRYPTION_ERROR", cause: error }
4454
- )
4455
- );
4456
- const stringified = yield* safeCipherStringify(encrypted);
4457
- return ok4(stringified);
4458
- });
6035
+ function normalizeSubgraphOrder(raw) {
6036
+ const ctx = { orderId: raw.orderId };
6037
+ return Result3.combine([
6038
+ mapOrderType(raw.type, ctx),
6039
+ mapOrderStatus(raw.status, ctx),
6040
+ mapDisputeStatus(raw.disputeStatus, ctx)
6041
+ ]).map(([type, status, disputeStatus]) => ({
6042
+ orderId: BigInt(raw.orderId),
6043
+ type,
6044
+ status,
6045
+ usdcAmount: BigInt(raw.usdcAmount),
6046
+ fiatAmount: BigInt(raw.fiatAmount),
6047
+ actualUsdcAmount: BigInt(raw.actualUsdcAmount),
6048
+ actualFiatAmount: BigInt(raw.actualFiatAmount),
6049
+ currency: decodeCurrency(raw.currency),
6050
+ user: raw.userAddress,
6051
+ recipient: raw.usdcRecipientAddress,
6052
+ acceptedMerchant: raw.acceptedMerchantAddress,
6053
+ placedAt: BigInt(raw.placedAt),
6054
+ acceptedAt: BigInt(raw.acceptedAt),
6055
+ paidAt: BigInt(raw.paidAt),
6056
+ completedAt: BigInt(raw.completedAt),
6057
+ circleId: BigInt(raw.circleId),
6058
+ fixedFeePaid: BigInt(raw.fixedFeePaid),
6059
+ tipsPaid: BigInt(raw.tipsPaid),
6060
+ disputeStatus,
6061
+ // Subgraph entity does not currently expose these encryption fields;
6062
+ // consumers needing them should fall back to the contract via getOrder.
6063
+ encUpi: "",
6064
+ encMerchantUpi: "",
6065
+ pubkey: ""
6066
+ }));
4459
6067
  }
4460
- var ZodEncryptedDataSchema = z7.object({
4461
- ciphertext: z7.string(),
4462
- iv: z7.string(),
4463
- mac: z7.string(),
4464
- ephemPublicKey: z7.string()
4465
- });
4466
6068
 
4467
- // src/payload/validation.ts
4468
- import { z as z8 } from "zod";
4469
- var ZodPlaceOrderParamsSchema = z8.object({
4470
- amount: z8.bigint(),
4471
- recipientAddr: ZodAddressSchema,
4472
- orderType: z8.number().int().min(0).max(2),
4473
- currency: ZodCurrencySchema,
4474
- fiatAmount: z8.bigint(),
4475
- user: ZodAddressSchema,
4476
- pubKey: z8.string().optional(),
4477
- preferredPaymentChannelConfigId: z8.bigint().optional(),
4478
- fiatAmountLimit: z8.bigint().optional().default(0n)
4479
- });
4480
- var ZodSetSellOrderUpiParamsSchema = z8.object({
4481
- orderId: z8.number().int().nonnegative(),
4482
- paymentAddress: z8.string().min(1),
4483
- merchantPublicKey: z8.string().min(1),
4484
- updatedAmount: z8.bigint()
4485
- });
6069
+ // src/orders/subgraph/index.ts
6070
+ import { Result as Result4 } from "neverthrow";
4486
6071
 
4487
- // src/payload/actions.ts
4488
- function buildPlaceOrderPayload(orderRouter, params) {
4489
- const validation = validate(
4490
- ZodPlaceOrderParamsSchema,
4491
- params,
4492
- (message, cause, data) => new PayloadError(message, { code: "VALIDATION_ERROR", cause, context: { data } })
4493
- );
4494
- if (validation.isErr()) {
4495
- return errAsync3(validation.error);
4496
- }
4497
- const v = validation.value;
4498
- const isBuy = v.orderType === ORDER_TYPE.BUY;
4499
- const pcConfigId = v.preferredPaymentChannelConfigId ?? 0n;
4500
- const circleResult = orderRouter.selectCircle({
4501
- currency: v.currency,
4502
- user: v.user,
4503
- usdtAmount: v.amount,
4504
- fiatAmount: v.fiatAmount,
4505
- orderType: BigInt(v.orderType),
4506
- preferredPCConfigId: pcConfigId
4507
- });
4508
- const relayResult = getRelayIdentity();
4509
- if (relayResult.isErr()) {
4510
- return errAsync3(relayResult.error);
4511
- }
4512
- const common = {
4513
- amount: v.amount,
4514
- recipientAddr: v.recipientAddr,
4515
- orderType: v.orderType,
4516
- userUpi: "",
4517
- currency: v.currency,
4518
- preferredPaymentChannelConfigId: pcConfigId,
4519
- fiatAmountLimit: v.fiatAmountLimit
4520
- };
4521
- const pubKeyValue = v.pubKey ?? relayResult.value.publicKey;
4522
- return circleResult.map((circleId) => ({
4523
- ...common,
4524
- pubKey: isBuy ? pubKeyValue : "",
4525
- userPubKey: isBuy ? "" : pubKeyValue,
4526
- circleId
4527
- })).mapErr(
4528
- (e) => new PayloadError(e.message, {
4529
- code: "CIRCLE_SELECTION_ERROR",
4530
- cause: e
6072
+ // src/orders/subgraph/queries.ts
6073
+ var ORDERS_BY_USER_QUERY = (
6074
+ /* GraphQL */
6075
+ `
6076
+ query OrdersByUser($user: Bytes!, $skip: Int!, $first: Int!) {
6077
+ orders_collection(
6078
+ where: { userAddress: $user }
6079
+ orderBy: placedAt
6080
+ orderDirection: desc
6081
+ skip: $skip
6082
+ first: $first
6083
+ ) {
6084
+ orderId
6085
+ type
6086
+ status
6087
+ circleId
6088
+ userAddress
6089
+ usdcRecipientAddress
6090
+ acceptedMerchantAddress
6091
+ usdcAmount
6092
+ fiatAmount
6093
+ actualUsdcAmount
6094
+ actualFiatAmount
6095
+ currency
6096
+ placedAt
6097
+ acceptedAt
6098
+ paidAt
6099
+ completedAt
6100
+ fixedFeePaid
6101
+ tipsPaid
6102
+ disputeStatus
6103
+ }
6104
+ }
6105
+ `
6106
+ );
6107
+
6108
+ // src/orders/subgraph/index.ts
6109
+ function getOrdersForUser(subgraphUrl, userAddress, skip, limit, logger = noopLogger) {
6110
+ const user = userAddress.toLowerCase();
6111
+ logger.debug("fetching orders from subgraph", { subgraphUrl, user, skip, limit });
6112
+ return querySubgraph(subgraphUrl, {
6113
+ query: ORDERS_BY_USER_QUERY,
6114
+ variables: { user, skip, first: limit }
6115
+ }).mapErr(
6116
+ (e) => new OrdersError(e.message, {
6117
+ code: "SUBGRAPH_REQUEST_FAILED",
6118
+ cause: e.cause ?? e,
6119
+ context: { user, skip, limit, ...e.context ?? {} }
4531
6120
  })
6121
+ ).andThen(
6122
+ (data) => validate(
6123
+ ZodSubgraphOrdersResponseSchema,
6124
+ data,
6125
+ (message, cause, d) => new OrdersError(message, {
6126
+ code: "SUBGRAPH_VALIDATION_FAILED",
6127
+ cause,
6128
+ context: { data: d }
6129
+ })
6130
+ ).andThen(
6131
+ (validated) => Result4.combine(validated.orders_collection.map(normalizeSubgraphOrder))
6132
+ )
4532
6133
  );
4533
6134
  }
4534
- function buildSetSellOrderUpiPayload(params) {
4535
- const validation = validate(
4536
- ZodSetSellOrderUpiParamsSchema,
4537
- params,
4538
- (message, cause, data) => new PayloadError(message, { code: "VALIDATION_ERROR", cause, context: { data } })
4539
- );
4540
- if (validation.isErr()) {
4541
- return errAsync3(validation.error);
4542
- }
4543
- const v = validation.value;
4544
- return encryptPaymentAddress(v.paymentAddress, v.merchantPublicKey).map((userEncUpi) => ({
4545
- orderId: v.orderId,
4546
- userEncUpi,
4547
- updatedAmount: v.updatedAmount
4548
- }));
6135
+
6136
+ // src/orders/watch-events.ts
6137
+ var PLACED_CONFIG = {
6138
+ eventName: "OrderPlaced",
6139
+ toEvent: (log) => ({
6140
+ type: "placed",
6141
+ orderId: log.args.orderId,
6142
+ user: log.args.user,
6143
+ orderType: log.args.orderType,
6144
+ blockNumber: log.blockNumber,
6145
+ txHash: log.transactionHash
6146
+ }),
6147
+ userFromLog: (log) => log.args.user
6148
+ };
6149
+ var ACCEPTED_CONFIG = {
6150
+ eventName: "OrderAccepted",
6151
+ toEvent: (log) => ({
6152
+ type: "accepted",
6153
+ orderId: log.args.orderId,
6154
+ merchant: log.args.merchant,
6155
+ blockNumber: log.blockNumber,
6156
+ txHash: log.transactionHash
6157
+ }),
6158
+ // OrderAccepted's top-level args are (orderId, merchant, pubKey, _order).
6159
+ // The buyer's address lives inside the _order tuple as _order.user.
6160
+ userFromLog: (log) => log.args._order?.user
6161
+ };
6162
+ var PAID_CONFIG = {
6163
+ eventName: "BuyOrderPaid",
6164
+ toEvent: (log) => ({
6165
+ type: "paid",
6166
+ orderId: log.args.orderId,
6167
+ blockNumber: log.blockNumber,
6168
+ txHash: log.transactionHash
6169
+ }),
6170
+ userFromLog: (log) => log.args.user
6171
+ };
6172
+ var COMPLETED_CONFIG = {
6173
+ eventName: "OrderCompleted",
6174
+ toEvent: (log) => ({
6175
+ type: "completed",
6176
+ orderId: log.args.orderId,
6177
+ blockNumber: log.blockNumber,
6178
+ txHash: log.transactionHash
6179
+ }),
6180
+ userFromLog: (log) => log.args.user
6181
+ };
6182
+ var CANCELLED_CONFIG = {
6183
+ eventName: "CancelledOrders",
6184
+ toEvent: (log) => ({
6185
+ type: "cancelled",
6186
+ orderId: log.args.orderId,
6187
+ blockNumber: log.blockNumber,
6188
+ txHash: log.transactionHash
6189
+ }),
6190
+ // CancelledOrders's top-level args are (orderId, _order). The buyer's
6191
+ // address lives inside the _order tuple as _order.user.
6192
+ userFromLog: (log) => log.args._order?.user
6193
+ };
6194
+ var ALL_CONFIGS = [
6195
+ PLACED_CONFIG,
6196
+ ACCEPTED_CONFIG,
6197
+ PAID_CONFIG,
6198
+ COMPLETED_CONFIG,
6199
+ CANCELLED_CONFIG
6200
+ ];
6201
+ function createWatchEvents(input) {
6202
+ const { publicClient, diamondAddress } = input;
6203
+ return ({ user, onEvent, onError }) => {
6204
+ const unwatchers = [];
6205
+ for (const config of ALL_CONFIGS) {
6206
+ try {
6207
+ const unwatch = publicClient.watchContractEvent({
6208
+ address: diamondAddress,
6209
+ abi: ABIS.DIAMOND,
6210
+ eventName: config.eventName,
6211
+ onLogs: (logs) => {
6212
+ for (const log of logs) {
6213
+ if (user && config.userFromLog) {
6214
+ const logUser = config.userFromLog(log);
6215
+ if (!logUser || logUser.toLowerCase() !== user.toLowerCase()) continue;
6216
+ }
6217
+ onEvent(config.toEvent(log));
6218
+ }
6219
+ },
6220
+ onError: (err5) => {
6221
+ onError?.(
6222
+ new OrdersError(`watchContractEvent failed for ${config.eventName}`, {
6223
+ code: "EVENT_WATCH_FAILED",
6224
+ cause: err5,
6225
+ context: { eventName: config.eventName }
6226
+ })
6227
+ );
6228
+ }
6229
+ });
6230
+ unwatchers.push(unwatch);
6231
+ } catch (err5) {
6232
+ onError?.(
6233
+ new OrdersError(`failed to subscribe to ${config.eventName}`, {
6234
+ code: "EVENT_WATCH_FAILED",
6235
+ cause: err5,
6236
+ context: { eventName: config.eventName }
6237
+ })
6238
+ );
6239
+ }
6240
+ }
6241
+ return () => {
6242
+ for (const u of unwatchers) {
6243
+ try {
6244
+ u();
6245
+ } catch {
6246
+ }
6247
+ }
6248
+ };
6249
+ };
4549
6250
  }
4550
6251
 
4551
- // src/payload/client.ts
4552
- function createPayloadGenerator(config) {
6252
+ // src/orders/client.ts
6253
+ function createOrders(config) {
6254
+ const { publicClient, diamondAddress, usdcAddress, subgraphUrl, relayIdentity } = config;
6255
+ const logger = config.logger ?? noopLogger;
6256
+ const relayIdentityStore = config.relayIdentityStore ?? createInMemoryRelayStore();
6257
+ const orderRouter = createOrderRouter({
6258
+ publicClient,
6259
+ subgraphUrl,
6260
+ contractAddress: diamondAddress,
6261
+ logger
6262
+ });
4553
6263
  return {
4554
- placeOrder(params) {
4555
- return buildPlaceOrderPayload(config.orderRouter, params);
6264
+ // ── Reads ─────────────────────────────────────────────────────────
6265
+ getOrder(params) {
6266
+ return validate(
6267
+ ZodGetOrderParamsSchema,
6268
+ params,
6269
+ (message, cause, d) => new OrdersError(message, {
6270
+ code: "INVALID_ORDER_ID",
6271
+ cause,
6272
+ context: { params: d }
6273
+ })
6274
+ ).asyncAndThen(
6275
+ ({ orderId }) => readOrderMulticall(publicClient, diamondAddress, orderId).mapErr(
6276
+ (cause) => new OrdersError("Order contract read failed", {
6277
+ code: "CONTRACT_READ_FAILED",
6278
+ cause,
6279
+ context: { orderId: orderId.toString() }
6280
+ })
6281
+ )
6282
+ ).andThen(
6283
+ ({ order, details }) => normalizeContractOrder(order, details).asyncAndThen((normalized) => {
6284
+ if (!normalized) {
6285
+ return errAsync4(
6286
+ new OrdersError("Order not found", {
6287
+ code: "ORDER_NOT_FOUND",
6288
+ context: { orderId: params.orderId.toString() }
6289
+ })
6290
+ );
6291
+ }
6292
+ logger.debug("getOrder resolved", { orderId: params.orderId.toString() });
6293
+ return okAsync4(normalized);
6294
+ })
6295
+ );
6296
+ },
6297
+ getOrders(params) {
6298
+ return validate(
6299
+ ZodGetOrdersParamsSchema,
6300
+ params,
6301
+ (message, cause, d) => new OrdersError(message, {
6302
+ code: "INVALID_GET_ORDERS_PARAMS",
6303
+ cause,
6304
+ context: { params: d }
6305
+ })
6306
+ ).asyncAndThen(
6307
+ ({ userAddress, skip, limit }) => getOrdersForUser(subgraphUrl, userAddress, skip, limit, logger)
6308
+ );
6309
+ },
6310
+ getFeeConfig(params) {
6311
+ return validate(
6312
+ ZodGetFeeConfigParamsSchema,
6313
+ params,
6314
+ (message, cause, d) => new OrdersError(message, {
6315
+ code: "INVALID_FEE_CONFIG_PARAMS",
6316
+ cause,
6317
+ context: { params: d }
6318
+ })
6319
+ ).asyncAndThen(
6320
+ ({ currency }) => readFeeConfigMulticall(publicClient, diamondAddress, currency).mapErr(
6321
+ (cause) => new OrdersError("Fee config contract read failed", {
6322
+ code: "CONTRACT_READ_FAILED",
6323
+ cause,
6324
+ context: { currency }
6325
+ })
6326
+ )
6327
+ ).map((config2) => {
6328
+ logger.debug("getFeeConfig resolved", { currency: params.currency });
6329
+ return config2;
6330
+ });
6331
+ },
6332
+ // ── Writes ────────────────────────────────────────────────────────
6333
+ placeOrder: createPlaceOrderAction({
6334
+ publicClient,
6335
+ diamondAddress,
6336
+ orderRouter,
6337
+ relayIdentityStore,
6338
+ relayIdentity
6339
+ }),
6340
+ cancelOrder: createCancelOrderAction({ publicClient, diamondAddress }),
6341
+ setSellOrderUpi: createSetSellOrderUpiAction({
6342
+ publicClient,
6343
+ diamondAddress,
6344
+ relayIdentityStore,
6345
+ relayIdentity
6346
+ }),
6347
+ raiseDispute: createRaiseDisputeAction({ publicClient, diamondAddress }),
6348
+ approveUsdc: createApproveUsdcAction({ publicClient, diamondAddress, usdcAddress }),
6349
+ paidBuyOrder: createPaidBuyOrderAction({ publicClient, diamondAddress }),
6350
+ watchEvents: createWatchEvents({ publicClient, diamondAddress }),
6351
+ // ── Crypto helpers ───────────────────────────────────────────────
6352
+ decryptPaymentAddress({ encrypted }) {
6353
+ return resolveRelayIdentity({ relayIdentity, store: relayIdentityStore }).andThen(
6354
+ (recipientIdentity) => decryptPaymentAddress({ encrypted, recipientIdentity })
6355
+ );
4556
6356
  },
4557
- setSellOrderUpi(params) {
4558
- return buildSetSellOrderUpiPayload(params);
6357
+ encryptPaymentAddress({ paymentAddress, recipientPublicKey }) {
6358
+ return resolveRelayIdentity({ relayIdentity, store: relayIdentityStore }).andThen(
6359
+ (senderIdentity) => encryptPaymentAddress({
6360
+ paymentAddress,
6361
+ recipientPublicKey,
6362
+ senderIdentity
6363
+ })
6364
+ );
4559
6365
  }
4560
6366
  };
4561
6367
  }
4562
6368
 
6369
+ // src/prices/client.ts
6370
+ function createPrices(config) {
6371
+ const { publicClient, diamondAddress } = config;
6372
+ return {
6373
+ getPriceConfig: (params) => getPriceConfig(publicClient, diamondAddress, params),
6374
+ getReputationPerUsdcLimit: (params) => getReputationPerUsdcLimit(publicClient, diamondAddress, params)
6375
+ };
6376
+ }
6377
+
4563
6378
  // src/profile/contracts/actions.ts
4564
- import { ResultAsync as ResultAsync8 } from "neverthrow";
6379
+ import { ResultAsync as ResultAsync11 } from "neverthrow";
4565
6380
  import { formatUnits as formatUnits2 } from "viem";
4566
6381
  function getBalances(publicClient, usdcAddress, diamondAddress, params) {
4567
6382
  return validate(
@@ -4573,13 +6388,19 @@ function getBalances(publicClient, usdcAddress, diamondAddress, params) {
4573
6388
  context: { params: data }
4574
6389
  })
4575
6390
  ).asyncAndThen(
4576
- (validated) => ResultAsync8.combine([
6391
+ (validated) => ResultAsync11.combine([
4577
6392
  getUsdcBalance(publicClient, usdcAddress, {
4578
6393
  address: validated.address
4579
6394
  }),
4580
6395
  getPriceConfig(publicClient, diamondAddress, {
4581
6396
  currency: validated.currency
4582
- })
6397
+ }).mapErr(
6398
+ (cause) => new ProfileError("Failed to read price config for balance conversion", {
6399
+ code: "CONTRACT_READ_ERROR",
6400
+ cause,
6401
+ context: { currency: validated.currency }
6402
+ })
6403
+ )
4583
6404
  ]).map(([usdc, priceConfig]) => {
4584
6405
  const usdcFormatted = Number(formatUnits2(usdc, 6));
4585
6406
  const sellPriceFormatted = Number(formatUnits2(priceConfig.sellPrice, 6));
@@ -4597,10 +6418,9 @@ function createProfile(config) {
4597
6418
  const { publicClient, diamondAddress, usdcAddress } = config;
4598
6419
  return {
4599
6420
  getUsdcBalance: (params) => getUsdcBalance(publicClient, usdcAddress, params),
4600
- getPriceConfig: (params) => getPriceConfig(publicClient, diamondAddress, params),
6421
+ getUsdcAllowance: (params) => getUsdcAllowance(publicClient, usdcAddress, diamondAddress, params),
4601
6422
  getBalances: (params) => getBalances(publicClient, usdcAddress, diamondAddress, params),
4602
- getTxLimits: (params) => getTxLimits(publicClient, diamondAddress, params),
4603
- getRpPerUsdtLimitRational: (params) => getRpPerUsdtLimitRational(publicClient, diamondAddress, params)
6423
+ getTxLimits: (params) => getTxLimits(publicClient, diamondAddress, params)
4604
6424
  };
4605
6425
  }
4606
6426
 
@@ -4641,21 +6461,28 @@ function SdkProvider({ children, ...config }) {
4641
6461
  initedRef.current = fraudEngine;
4642
6462
  fraudEngine.init();
4643
6463
  }, [fraudEngine]);
6464
+ const relayIdentityStore = config.orders?.relayIdentityStore;
6465
+ const relayIdentity = config.orders?.relayIdentity;
4644
6466
  const sdk = useMemo(() => {
4645
- const orderRouter = createOrderRouter({
4646
- publicClient,
4647
- subgraphUrl: config.subgraphUrl,
4648
- contractAddress: config.diamondAddress,
4649
- logger
4650
- });
4651
6467
  return {
4652
6468
  profile: createProfile({
4653
6469
  publicClient,
4654
6470
  diamondAddress: config.diamondAddress,
4655
6471
  usdcAddress: config.usdcAddress
4656
6472
  }),
4657
- orderRouter,
4658
- payload: createPayloadGenerator({ orderRouter }),
6473
+ prices: createPrices({
6474
+ publicClient,
6475
+ diamondAddress: config.diamondAddress
6476
+ }),
6477
+ orders: createOrders({
6478
+ publicClient,
6479
+ diamondAddress: config.diamondAddress,
6480
+ usdcAddress: config.usdcAddress,
6481
+ subgraphUrl: config.subgraphUrl,
6482
+ relayIdentityStore,
6483
+ relayIdentity,
6484
+ logger
6485
+ }),
4659
6486
  zkkyc: config.reputationManagerAddress ? createZkkyc({
4660
6487
  reputationManagerAddress: config.reputationManagerAddress
4661
6488
  }) : void 0,
@@ -4667,6 +6494,8 @@ function SdkProvider({ children, ...config }) {
4667
6494
  config.diamondAddress,
4668
6495
  config.usdcAddress,
4669
6496
  config.reputationManagerAddress,
6497
+ relayIdentityStore,
6498
+ relayIdentity,
4670
6499
  logger,
4671
6500
  fraudEngine
4672
6501
  ]);
@@ -4682,11 +6511,11 @@ function useSdk() {
4682
6511
  function useProfile() {
4683
6512
  return useSdk().profile;
4684
6513
  }
4685
- function useOrderRouter() {
4686
- return useSdk().orderRouter;
6514
+ function usePrices() {
6515
+ return useSdk().prices;
4687
6516
  }
4688
- function usePayloadGenerator() {
4689
- return useSdk().payload;
6517
+ function useOrders() {
6518
+ return useSdk().orders;
4690
6519
  }
4691
6520
  function useZkkyc() {
4692
6521
  const zkkyc = useSdk().zkkyc;
@@ -4703,13 +6532,32 @@ function useFraudEngine() {
4703
6532
  return fraudEngine;
4704
6533
  }
4705
6534
 
6535
+ // src/react/use-watch-orders.ts
6536
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
6537
+ function useWatchOrders(params) {
6538
+ const orders = useOrders();
6539
+ const { user, onEvent, onError } = params;
6540
+ const onEventRef = useRef2(onEvent);
6541
+ const onErrorRef = useRef2(onError);
6542
+ onEventRef.current = onEvent;
6543
+ onErrorRef.current = onError;
6544
+ useEffect2(() => {
6545
+ const unsubscribe = orders.watchEvents({
6546
+ user,
6547
+ onEvent: (event) => onEventRef.current(event),
6548
+ onError: (error) => onErrorRef.current?.(error)
6549
+ });
6550
+ return unsubscribe;
6551
+ }, [orders, user]);
6552
+ }
6553
+
4706
6554
  // src/fraud-engine/react/use-fingerprint.ts
4707
- import { useEffect as useEffect2, useState } from "react";
6555
+ import { useEffect as useEffect3, useState } from "react";
4708
6556
  function useFingerprint(enabled) {
4709
6557
  const [data, setData] = useState(null);
4710
6558
  const [error, setError] = useState(null);
4711
6559
  const [isLoading, setIsLoading] = useState(false);
4712
- useEffect2(() => {
6560
+ useEffect3(() => {
4713
6561
  if (!enabled) return;
4714
6562
  let cancelled = false;
4715
6563
  setIsLoading(true);
@@ -4740,10 +6588,11 @@ export {
4740
6588
  SdkProvider,
4741
6589
  useFingerprint,
4742
6590
  useFraudEngine,
4743
- useOrderRouter,
4744
- usePayloadGenerator,
6591
+ useOrders,
6592
+ usePrices,
4745
6593
  useProfile,
4746
6594
  useSdk,
6595
+ useWatchOrders,
4747
6596
  useZkkyc
4748
6597
  };
4749
6598
  /*! Bundled license information: