@p2pdotme/sdk 1.0.5 → 1.1.0

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 (64) hide show
  1. package/README.md +71 -41
  2. package/dist/country.cjs +8 -1
  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 +5 -1
  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/{payload.cjs → orders.cjs} +2357 -253
  19. package/dist/orders.cjs.map +1 -0
  20. package/dist/orders.d.cts +399 -0
  21. package/dist/orders.d.ts +399 -0
  22. package/dist/{payload.mjs → orders.mjs} +2340 -237
  23. package/dist/orders.mjs.map +1 -0
  24. package/dist/prices.cjs +1008 -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 +980 -0
  29. package/dist/prices.mjs.map +1 -0
  30. package/dist/profile.cjs +475 -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 +468 -62
  35. package/dist/profile.mjs.map +1 -1
  36. package/dist/qr-parsers.cjs +6 -6
  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 +6 -6
  41. package/dist/qr-parsers.mjs.map +1 -1
  42. package/dist/react.cjs +2531 -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 +2417 -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.map +0 -1
  62. package/dist/payload.d.cts +0 -147
  63. package/dist/payload.d.ts +0 -147
  64. 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,1322 @@ 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/order-flow/index.ts
4863
+ import { ResultAsync as ResultAsync7 } from "neverthrow";
4864
+
4865
+ // src/orders/internal/routing/errors.ts
4866
+ var OrderRoutingError = class extends SdkError {
4867
+ constructor(message, options) {
4868
+ super(message, options);
4869
+ this.name = "OrderRoutingError";
4870
+ }
4871
+ };
4872
+
4873
+ // src/orders/internal/routing/validation.ts
4874
+ import { z as z6 } from "zod";
4875
+ var ZodCircleScoreStateSchema = z6.object({
4876
+ activeMerchantsCount: z6.coerce.number()
4877
+ });
4878
+ var ZodCircleMetricsForRoutingSchema = z6.object({
4879
+ circleScore: z6.coerce.number(),
4880
+ circleStatus: z6.string(),
4881
+ scoreState: ZodCircleScoreStateSchema
4882
+ });
4883
+ var ZodCircleForRoutingSchema = z6.object({
4884
+ circleId: z6.string(),
4885
+ currency: z6.string(),
4886
+ metrics: ZodCircleMetricsForRoutingSchema
4887
+ });
4888
+ var ZodCirclesForRoutingResponseSchema = z6.object({
4889
+ circles: z6.array(ZodCircleForRoutingSchema)
4890
+ });
4891
+ var ZodCheckCircleEligibilityParamsSchema = z6.object({
4892
+ circleId: z6.bigint(),
4893
+ currency: z6.string(),
4894
+ user: ZodAddressSchema,
4895
+ usdtAmount: z6.bigint(),
4896
+ fiatAmount: z6.bigint(),
4897
+ orderType: z6.bigint(),
4898
+ preferredPCConfigId: z6.bigint()
4899
+ });
4900
+ var ZodSelectCircleParamsSchema = z6.object({
4901
+ currency: z6.string().min(1),
4902
+ user: ZodAddressSchema,
4903
+ usdtAmount: z6.bigint(),
4904
+ fiatAmount: z6.bigint(),
4905
+ orderType: z6.bigint(),
4906
+ preferredPCConfigId: z6.bigint()
4907
+ });
4908
+
4909
+ // src/contracts/order-flow/index.ts
4910
+ function checkCircleEligibility(publicClient, contractAddress, params, logger = noopLogger) {
4911
+ return validate(
4912
+ ZodCheckCircleEligibilityParamsSchema,
4913
+ params,
4914
+ (message, cause, d) => new OrderRoutingError(message, { code: "VALIDATION_ERROR", cause, context: { data: d } })
4915
+ ).asyncAndThen((validated) => {
4916
+ logger.debug("checking on-chain eligibility", {
4917
+ circleId: String(validated.circleId),
4918
+ contractAddress
4919
+ });
4920
+ return ResultAsync7.fromPromise(
4921
+ publicClient.readContract({
4922
+ address: contractAddress,
4923
+ abi: ABIS.FACETS.ORDER_FLOW,
4924
+ functionName: "getAssignableMerchantsFromCircle",
4925
+ args: [
4926
+ validated.circleId,
4927
+ 1n,
4928
+ validated.currency,
4929
+ validated.user,
4930
+ validated.usdtAmount,
4931
+ validated.fiatAmount,
4932
+ validated.orderType,
4933
+ validated.preferredPCConfigId
4934
+ ]
4935
+ }),
4936
+ (error) => new OrderRoutingError("Eligibility check failed", {
4937
+ code: "CONTRACT_READ_ERROR",
4938
+ cause: error,
4939
+ context: { circleId: String(params.circleId) }
4940
+ })
4941
+ );
4942
+ }).map((merchants) => {
4943
+ const arr = merchants;
4944
+ const eligible = arr.length >= 1;
4945
+ logger.debug("eligibility check result", {
4946
+ circleId: String(params.circleId),
4947
+ assignableMerchants: arr.length,
4948
+ eligible
4949
+ });
4950
+ return eligible;
4951
+ });
4952
+ }
4953
+
4954
+ // src/contracts/p2p-config/index.ts
4955
+ import { ResultAsync as ResultAsync8 } from "neverthrow";
4956
+ import { stringToHex as stringToHex4 } from "viem";
4957
+
4958
+ // src/prices/errors.ts
4959
+ var PricesError = class extends SdkError {
4960
+ constructor(message, options) {
4961
+ super(message, options);
4962
+ this.name = "PricesError";
4963
+ }
4964
+ };
4965
+
4966
+ // src/prices/validation.ts
4967
+ import { z as z7 } from "zod";
4968
+ var ZodCurrencyScopedParamsSchema = z7.object({
4969
+ currency: ZodCurrencySchema
4970
+ });
4971
+
4972
+ // src/contracts/p2p-config/index.ts
4973
+ function getPriceConfig(publicClient, diamondAddress, params) {
4974
+ return validate(
4975
+ ZodCurrencyScopedParamsSchema,
4976
+ params,
4977
+ (message, cause, data) => new PricesError(message, {
4978
+ code: "VALIDATION_ERROR",
4979
+ cause,
4980
+ context: { params: data }
4981
+ })
4982
+ ).asyncAndThen(
4983
+ (validated) => ResultAsync8.fromPromise(
4984
+ publicClient.readContract({
4985
+ address: diamondAddress,
4986
+ abi: ABIS.FACETS.CONFIG,
4987
+ functionName: "getPriceConfig",
4988
+ args: [stringToHex4(validated.currency, { size: 32 })]
4989
+ }),
4990
+ (error) => new PricesError("Failed to read price config", {
4991
+ code: "CONTRACT_READ_ERROR",
4992
+ cause: error,
4993
+ context: { currency: validated.currency, diamondAddress }
4994
+ })
4995
+ )
4996
+ );
4997
+ }
4998
+ function getReputationPerUsdcLimit(publicClient, diamondAddress, params) {
4999
+ return validate(
5000
+ ZodCurrencyScopedParamsSchema,
5001
+ params,
5002
+ (message, cause, data) => new PricesError(message, {
5003
+ code: "VALIDATION_ERROR",
5004
+ cause,
5005
+ context: { params: data }
5006
+ })
5007
+ ).asyncAndThen(
5008
+ (validated) => ResultAsync8.fromPromise(
5009
+ publicClient.readContract({
5010
+ address: diamondAddress,
5011
+ abi: ABIS.DIAMOND,
5012
+ functionName: "getRpPerUsdtLimitRational",
5013
+ args: [stringToHex4(validated.currency, { size: 32 })]
5014
+ }),
5015
+ (error) => new PricesError("Failed to read reputation-per-USDC limit", {
5016
+ code: "CONTRACT_READ_ERROR",
5017
+ cause: error,
5018
+ context: { currency: validated.currency, diamondAddress }
5019
+ })
5020
+ ).map(([numerator, denominator]) => ({
5021
+ numerator,
5022
+ denominator,
5023
+ multiplier: numerator > 0n ? Number(denominator) / Number(numerator) : 0
5024
+ }))
5025
+ );
5026
+ }
5027
+
5028
+ // src/contracts/reputation-manager/writes.ts
5029
+ import { Result as Result2 } from "neverthrow";
5030
+ import { encodeFunctionData as encodeFunctionData7 } from "viem";
5031
+
5032
+ // src/zkkyc/errors.ts
5033
+ var ZkkycError = class extends SdkError {
5034
+ constructor(message, options) {
5035
+ super(message, options);
5036
+ this.name = "ZkkycError";
5037
+ }
5038
+ };
5039
+
5040
+ // src/zkkyc/validation.ts
5041
+ import { z as z8 } from "zod";
5042
+ var ZodAnonAadharProofParamsSchema = z8.object({
5043
+ nullifierSeed: z8.bigint(),
5044
+ nullifier: z8.bigint(),
5045
+ timestamp: z8.bigint(),
5046
+ signal: z8.bigint(),
5047
+ revealArray: z8.tuple([z8.bigint(), z8.bigint(), z8.bigint(), z8.bigint()]),
5048
+ packedGroth16Proof: z8.tuple([
5049
+ z8.bigint(),
5050
+ z8.bigint(),
5051
+ z8.bigint(),
5052
+ z8.bigint(),
5053
+ z8.bigint(),
5054
+ z8.bigint(),
5055
+ z8.bigint(),
5056
+ z8.bigint()
5057
+ ])
5058
+ });
5059
+ var ZodSocialVerifyParamsSchema = z8.object({
5060
+ _socialName: z8.string(),
5061
+ proofs: z8.array(
5062
+ z8.object({
5063
+ claimInfo: z8.object({
5064
+ provider: z8.string(),
5065
+ parameters: z8.string(),
5066
+ context: z8.string()
5067
+ }),
5068
+ signedClaim: z8.object({
5069
+ claim: z8.object({
5070
+ identifier: z8.string(),
5071
+ owner: ZodAddressSchema,
5072
+ timestampS: z8.number(),
5073
+ epoch: z8.number()
5074
+ }),
5075
+ signatures: z8.array(z8.string())
5076
+ })
5077
+ })
5078
+ )
5079
+ });
5080
+ var ZodSolidityVerifierParametersSchema = z8.object({
5081
+ version: z8.string().refine((val) => val.startsWith("0x"), {
5082
+ message: "Version must be a hex string"
5083
+ }),
5084
+ proofVerificationData: z8.object({
5085
+ vkeyHash: z8.string().refine((val) => /^0x[a-fA-F0-9]{64}$/.test(val), {
5086
+ message: "Invalid bytes32 hex string"
5087
+ }),
5088
+ proof: z8.string().refine((val) => val.startsWith("0x"), {
5089
+ message: "Proof must be a hex string"
5090
+ }),
5091
+ publicInputs: z8.array(
5092
+ z8.string().refine((val) => /^0x[a-fA-F0-9]{64}$/.test(val), {
5093
+ message: "Each public input must be a valid bytes32 hex string"
5094
+ })
5095
+ )
5096
+ }),
5097
+ committedInputs: z8.string().refine((val) => val.startsWith("0x"), {
5098
+ message: "Committed inputs must be a hex string"
5099
+ }),
5100
+ serviceConfig: z8.object({
5101
+ validityPeriodInSeconds: z8.number().int().nonnegative(),
5102
+ domain: z8.string(),
5103
+ scope: z8.string(),
5104
+ devMode: z8.boolean()
5105
+ })
5106
+ });
5107
+ var ZodZkPassportRegisterParamsSchema = z8.object({
5108
+ params: ZodSolidityVerifierParametersSchema,
5109
+ isIDCard: z8.boolean()
5110
+ });
5111
+
5112
+ // src/contracts/reputation-manager/writes.ts
5113
+ function prepareSocialVerify(reputationManagerAddress, params) {
5114
+ return validate(
5115
+ ZodSocialVerifyParamsSchema,
5116
+ params,
5117
+ (message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
5118
+ ).andThen(
5119
+ (validated) => Result2.fromThrowable(
5120
+ () => ({
5121
+ to: reputationManagerAddress,
5122
+ data: encodeFunctionData7({
5123
+ abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
5124
+ functionName: "socialVerify",
5125
+ args: [
5126
+ validated._socialName,
5127
+ validated.proofs.map((proof) => ({
5128
+ ...proof,
5129
+ signedClaim: {
5130
+ ...proof.signedClaim,
5131
+ claim: {
5132
+ ...proof.signedClaim.claim,
5133
+ identifier: proof.signedClaim.claim.identifier
5134
+ },
5135
+ signatures: proof.signedClaim.signatures
5136
+ }
5137
+ }))
5138
+ ]
5139
+ })
5140
+ }),
5141
+ (error) => new ZkkycError("Failed to encode socialVerify", {
5142
+ code: "ENCODE_ERROR",
5143
+ cause: error
5144
+ })
5145
+ )()
5146
+ );
5147
+ }
5148
+ function prepareSubmitAnonAadharProof(reputationManagerAddress, params) {
5149
+ return validate(
5150
+ ZodAnonAadharProofParamsSchema,
5151
+ params,
5152
+ (message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
5153
+ ).andThen(
5154
+ (validated) => Result2.fromThrowable(
5155
+ () => ({
5156
+ to: reputationManagerAddress,
5157
+ data: encodeFunctionData7({
5158
+ abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
5159
+ functionName: "submitAnonAadharProof",
5160
+ args: [
5161
+ validated.nullifierSeed,
5162
+ validated.nullifier,
5163
+ validated.timestamp,
5164
+ validated.signal,
5165
+ validated.revealArray,
5166
+ validated.packedGroth16Proof
5167
+ ]
5168
+ })
5169
+ }),
5170
+ (error) => new ZkkycError("Failed to encode submitAnonAadharProof", {
5171
+ code: "ENCODE_ERROR",
5172
+ cause: error
5173
+ })
5174
+ )()
5175
+ );
5176
+ }
5177
+ function prepareZkPassportRegister(reputationManagerAddress, params) {
5178
+ return validate(
5179
+ ZodZkPassportRegisterParamsSchema,
5180
+ params,
5181
+ (message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
5182
+ ).andThen(
5183
+ (validated) => Result2.fromThrowable(
5184
+ () => {
5185
+ const { proofVerificationData, serviceConfig, committedInputs, version } = validated.params;
5186
+ const proofVerificationParams = {
5187
+ version,
5188
+ proofVerificationData: {
5189
+ vkeyHash: proofVerificationData.vkeyHash,
5190
+ proof: proofVerificationData.proof,
5191
+ publicInputs: proofVerificationData.publicInputs
5192
+ },
5193
+ committedInputs,
5194
+ serviceConfig: {
5195
+ validityPeriodInSeconds: BigInt(serviceConfig.validityPeriodInSeconds),
5196
+ domain: serviceConfig.domain,
5197
+ scope: serviceConfig.scope,
5198
+ devMode: serviceConfig.devMode
5199
+ }
5200
+ };
5201
+ return {
5202
+ to: reputationManagerAddress,
5203
+ data: encodeFunctionData7({
5204
+ abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
5205
+ functionName: "zkPassportRegister",
5206
+ args: [proofVerificationParams, validated.isIDCard]
5207
+ })
5208
+ };
5209
+ },
5210
+ (error) => new ZkkycError("Failed to encode zkPassportRegister", {
5211
+ code: "ENCODE_ERROR",
5212
+ cause: error
5213
+ })
5214
+ )()
5215
+ );
5216
+ }
5217
+
5218
+ // src/contracts/tx-limits/index.ts
5219
+ import { ResultAsync as ResultAsync9 } from "neverthrow";
5220
+ import { formatUnits, stringToHex as stringToHex5 } from "viem";
5221
+
5222
+ // src/profile/errors.ts
5223
+ var ProfileError = class extends SdkError {
5224
+ constructor(message, options) {
5225
+ super(message, options);
5226
+ this.name = "ProfileError";
5227
+ }
5228
+ };
5229
+
5230
+ // src/profile/validation.ts
5231
+ import { z as z9 } from "zod";
5232
+ var ZodUsdcBalanceParamsSchema = z9.object({
5233
+ address: ZodAddressSchema
5234
+ });
5235
+ var ZodUsdcAllowanceParamsSchema = z9.object({
5236
+ owner: ZodAddressSchema
5237
+ });
5238
+ var ZodGetBalancesParamsSchema = z9.object({
5239
+ address: ZodAddressSchema,
5240
+ currency: ZodCurrencySchema
5241
+ });
5242
+ var ZodTxLimitsParamsSchema = z9.object({
5243
+ address: ZodAddressSchema,
5244
+ currency: ZodCurrencySchema
5245
+ });
5246
+
5247
+ // src/contracts/tx-limits/index.ts
5248
+ function getTxLimits(publicClient, diamondAddress, params) {
5249
+ return validate(
5250
+ ZodTxLimitsParamsSchema,
5251
+ params,
5252
+ (message, cause, data) => new ProfileError(message, {
5253
+ code: "VALIDATION_ERROR",
5254
+ cause,
5255
+ context: { params: data }
5256
+ })
5257
+ ).asyncAndThen(
5258
+ (validated) => ResultAsync9.fromPromise(
5259
+ publicClient.readContract({
5260
+ address: diamondAddress,
5261
+ abi: ABIS.FACETS.ORDER_FLOW,
5262
+ functionName: "userTxLimit",
5263
+ args: [validated.address, stringToHex5(validated.currency, { size: 32 })]
5264
+ }),
5265
+ (error) => new ProfileError("Failed to read tx limits", {
5266
+ code: "CONTRACT_READ_ERROR",
5267
+ cause: error,
5268
+ context: { address: validated.address, currency: validated.currency, diamondAddress }
5269
+ })
5270
+ ).map(([buyLimit, sellLimit]) => ({
5271
+ buyLimit: Number(formatUnits(buyLimit, 6)),
5272
+ sellLimit: Number(formatUnits(sellLimit, 6))
5273
+ }))
5274
+ );
5275
+ }
5276
+
5277
+ // src/contracts/usdc/index.ts
5278
+ import { ResultAsync as ResultAsync10 } from "neverthrow";
5279
+ import { erc20Abi as erc20Abi3 } from "viem";
5280
+ function getUsdcBalance(publicClient, usdcAddress, params) {
5281
+ return validate(
5282
+ ZodUsdcBalanceParamsSchema,
5283
+ params,
5284
+ (message, cause, data) => new ProfileError(message, {
5285
+ code: "VALIDATION_ERROR",
5286
+ cause,
5287
+ context: { params: data }
5288
+ })
5289
+ ).asyncAndThen(
5290
+ (validated) => ResultAsync10.fromPromise(
5291
+ publicClient.readContract({
5292
+ address: usdcAddress,
5293
+ abi: ABIS.EXTERNAL.USDC,
5294
+ functionName: "balanceOf",
5295
+ args: [validated.address]
5296
+ }),
5297
+ (error) => new ProfileError("Failed to read USDC balance", {
5298
+ code: "CONTRACT_READ_ERROR",
5299
+ cause: error,
5300
+ context: { address: validated.address, usdcAddress }
5301
+ })
5302
+ )
5303
+ );
5304
+ }
5305
+ function getUsdcAllowance(publicClient, usdcAddress, diamondAddress, params) {
5306
+ return validate(
5307
+ ZodUsdcAllowanceParamsSchema,
5308
+ params,
5309
+ (message, cause, data) => new ProfileError(message, {
5310
+ code: "VALIDATION_ERROR",
5311
+ cause,
5312
+ context: { params: data }
5313
+ })
5314
+ ).asyncAndThen(
5315
+ (validated) => ResultAsync10.fromPromise(
5316
+ publicClient.readContract({
5317
+ address: usdcAddress,
5318
+ abi: erc20Abi3,
5319
+ functionName: "allowance",
5320
+ args: [validated.owner, diamondAddress]
5321
+ }),
5322
+ (error) => new ProfileError("Failed to read USDC allowance", {
5323
+ code: "CONTRACT_READ_ERROR",
5324
+ cause: error,
5325
+ context: { owner: validated.owner, usdcAddress, diamondAddress }
5326
+ })
5327
+ )
5328
+ );
5329
+ }
5330
+
5331
+ // src/orders/internal/routing/routing.ts
5332
+ import { errAsync as errAsync3, okAsync as okAsync3 } from "neverthrow";
5333
+ var EPSILON = 0.25;
5334
+ var RECOVERY_SCALE = 0.3;
5335
+ var BOOTSTRAP_MAX_WEIGHT = 25;
5336
+ var MAX_VALIDATION_ATTEMPTS = 3;
5337
+ function circleWeight(c) {
5338
+ const score = c.metrics.circleScore;
5339
+ if (c.metrics.circleStatus === "paused") {
5340
+ return score * RECOVERY_SCALE;
5341
+ }
5342
+ if (c.metrics.circleStatus === "bootstrap") {
5343
+ return Math.min(score, BOOTSTRAP_MAX_WEIGHT);
5344
+ }
5345
+ return score;
5346
+ }
5347
+ function filterEligibleCircles(circles, orderCurrency) {
5348
+ return circles.filter((c) => c.currency.toLowerCase() === orderCurrency.toLowerCase());
5349
+ }
5350
+ function weightedRandomChoice(arr, weights) {
5351
+ const totalWeight = weights.reduce((sum, w) => sum + w, 0);
5352
+ if (totalWeight === 0) {
5353
+ return arr[Math.floor(Math.random() * arr.length)];
5354
+ }
5355
+ let rand = Math.random() * totalWeight;
5356
+ for (let i = 0; i < arr.length; i++) {
5357
+ rand -= weights[i];
5358
+ if (rand <= 0) {
5359
+ return arr[i];
5360
+ }
5361
+ }
5362
+ return arr[arr.length - 1];
5363
+ }
5364
+ function selectCircle(eligible) {
5365
+ if (eligible.length === 0) {
5366
+ return null;
5367
+ }
5368
+ const activeCircles = eligible.filter((c) => c.metrics.circleStatus === "active");
5369
+ const isExplore = Math.random() < EPSILON;
5370
+ if (isExplore) {
5371
+ const weights2 = eligible.map(circleWeight);
5372
+ return weightedRandomChoice(eligible, weights2);
5373
+ }
5374
+ if (activeCircles.length === 0) {
5375
+ const weights2 = eligible.map(circleWeight);
5376
+ return weightedRandomChoice(eligible, weights2);
5377
+ }
5378
+ const weights = activeCircles.map((c) => c.metrics.circleScore);
5379
+ return weightedRandomChoice(activeCircles, weights);
5380
+ }
5381
+ function selectCircleForOrderAsync(circles, orderCurrency, validateCircle, logger = noopLogger) {
5382
+ const eligible = filterEligibleCircles(circles, orderCurrency);
5383
+ let remaining = [...eligible];
5384
+ logger.debug("filtering eligible circles", {
5385
+ total: circles.length,
5386
+ eligible: eligible.length,
5387
+ currency: orderCurrency,
5388
+ circles: eligible
5389
+ });
5390
+ if (eligible.length === 0) {
5391
+ logger.warn("no eligible circles found for currency", { currency: orderCurrency });
5392
+ }
5393
+ function attempt(attemptsLeft) {
5394
+ if (attemptsLeft <= 0 || remaining.length === 0) {
5395
+ logger.warn("exhausted all attempts or circles", {
5396
+ attemptsLeft,
5397
+ remainingCircles: remaining.length
5398
+ });
5399
+ return errAsync3(
5400
+ new OrderRoutingError("No eligible circles found", {
5401
+ code: "NO_ELIGIBLE_CIRCLES"
5402
+ })
5403
+ );
5404
+ }
5405
+ const selected = selectCircle(remaining);
5406
+ if (!selected) {
5407
+ return errAsync3(
5408
+ new OrderRoutingError("No eligible circles found", {
5409
+ code: "NO_ELIGIBLE_CIRCLES"
5410
+ })
5411
+ );
5412
+ }
5413
+ const circleId = BigInt(selected.circleId);
5414
+ logger.debug("selected circle, validating on-chain", {
5415
+ circleId: String(circleId),
5416
+ status: selected.metrics.circleStatus,
5417
+ score: selected.metrics.circleScore,
5418
+ attemptsLeft
5419
+ });
5420
+ return validateCircle(circleId).orElse((error) => {
5421
+ logger.warn("validation errored, treating as ineligible", {
5422
+ circleId: String(circleId),
5423
+ error: String(error)
5424
+ });
5425
+ return okAsync3(false);
5426
+ }).andThen((isValid) => {
5427
+ if (isValid) {
5428
+ logger.info("circle validated successfully", { circleId: String(circleId) });
5429
+ return okAsync3(circleId);
5430
+ }
5431
+ logger.debug("circle failed validation, retrying", {
5432
+ circleId: String(circleId),
5433
+ remainingCircles: remaining.length - 1
5434
+ });
5435
+ remaining = remaining.filter((c) => c.circleId !== selected.circleId);
5436
+ return attempt(attemptsLeft - 1);
5437
+ });
5438
+ }
5439
+ return attempt(MAX_VALIDATION_ATTEMPTS);
5440
+ }
5441
+
5442
+ // src/orders/internal/routing/subgraph/queries.ts
5443
+ var CIRCLES_FOR_ROUTING_QUERY = (
5444
+ /* GraphQL */
5445
+ `
5446
+ query CirclesForRouting($currency: Bytes!) {
5447
+ circles(
5448
+ first: 1000
5449
+ where: {
5450
+ currency: $currency
5451
+ metrics_: {
5452
+ circleStatus_in: ["active", "bootstrap", "paused"]
5453
+ }
5454
+ }
5455
+ ) {
5456
+ circleId
5457
+ currency
5458
+ metrics {
5459
+ circleScore
5460
+ circleStatus
5461
+ scoreState {
5462
+ activeMerchantsCount
5463
+ }
5464
+ }
5465
+ }
5466
+ }
5467
+ `
5468
+ );
5469
+
5470
+ // src/orders/internal/routing/subgraph/index.ts
5471
+ function getCirclesForRouting(subgraphUrl, currency, logger = noopLogger) {
5472
+ logger.debug("fetching circles from subgraph", { subgraphUrl, currency });
5473
+ return querySubgraph(subgraphUrl, {
5474
+ query: CIRCLES_FOR_ROUTING_QUERY,
5475
+ variables: { currency }
5476
+ }).mapErr(
5477
+ (e) => new OrderRoutingError(e.message, {
5478
+ code: "SUBGRAPH_ERROR",
5479
+ cause: e.cause ?? e,
5480
+ context: e.context
5481
+ })
5482
+ ).andThen(
5483
+ (data) => validate(
5484
+ ZodCirclesForRoutingResponseSchema,
5485
+ data,
5486
+ (message, cause, d) => new OrderRoutingError(message, { code: "VALIDATION_ERROR", cause, context: { data: d } })
5487
+ ).map((validated) => {
5488
+ const circles = validated.circles.filter(
5489
+ (item) => Number(item.metrics.scoreState.activeMerchantsCount) > 0
5490
+ );
5491
+ logger.info("fetched circles from subgraph", {
5492
+ total: validated.circles.length,
5493
+ withActiveMerchants: circles.length,
5494
+ circles
5495
+ });
5496
+ return circles;
5497
+ })
5498
+ );
4337
5499
  }
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);
5500
+
5501
+ // src/orders/internal/routing/client.ts
5502
+ function createOrderRouter(config) {
5503
+ const { subgraphUrl, publicClient, contractAddress } = config;
5504
+ const logger = config.logger ?? noopLogger;
4351
5505
  return {
4352
- iv: bytesToHex2(iv),
4353
- ephemPublicKey: bytesToHex2(ephemPubKey),
4354
- ciphertext: bytesToHex2(ciphertext),
4355
- mac: bytesToHex2(mac)
5506
+ selectCircle(params) {
5507
+ const currencyHex = stringToHex6(params.currency, { size: 32 });
5508
+ logger.info("selectCircle started", {
5509
+ currency: params.currency,
5510
+ user: params.user,
5511
+ orderType: String(params.orderType)
5512
+ });
5513
+ return getCirclesForRouting(subgraphUrl, currencyHex, logger).andThen(
5514
+ (circles) => selectCircleForOrderAsync(
5515
+ circles,
5516
+ currencyHex,
5517
+ (circleId) => checkCircleEligibility(
5518
+ publicClient,
5519
+ contractAddress,
5520
+ {
5521
+ circleId,
5522
+ currency: currencyHex,
5523
+ user: params.user,
5524
+ usdtAmount: params.usdtAmount,
5525
+ fiatAmount: params.fiatAmount,
5526
+ orderType: params.orderType,
5527
+ preferredPCConfigId: params.preferredPCConfigId
5528
+ },
5529
+ logger
5530
+ ),
5531
+ logger
5532
+ )
5533
+ );
5534
+ }
4356
5535
  };
4357
5536
  }
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
5537
 
4367
- // src/payload/errors.ts
4368
- var PayloadError = class extends SdkError {
4369
- constructor(message, options) {
4370
- super(message, options);
4371
- this.name = "PayloadError";
4372
- }
5538
+ // src/orders/normalize.ts
5539
+ import { err as err4, ok as ok5, Result as Result3 } from "neverthrow";
5540
+ import { hexToString, isAddressEqual, zeroAddress } from "viem";
5541
+ var ORDER_TYPE_MAP = {
5542
+ [ORDER_TYPE.BUY]: "buy",
5543
+ [ORDER_TYPE.SELL]: "sell",
5544
+ [ORDER_TYPE.PAY]: "pay"
4373
5545
  };
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;
5546
+ var ORDER_STATUS_MAP = {
5547
+ [ORDER_STATUS.PLACED]: "placed",
5548
+ [ORDER_STATUS.ACCEPTED]: "accepted",
5549
+ [ORDER_STATUS.PAID]: "paid",
5550
+ [ORDER_STATUS.COMPLETED]: "completed",
5551
+ [ORDER_STATUS.CANCELLED]: "cancelled"
5552
+ };
5553
+ var DISPUTE_STATUS_MAP = {
5554
+ [DISPUTE_STATUS.NONE]: "none",
5555
+ [DISPUTE_STATUS.OPEN]: "open",
5556
+ [DISPUTE_STATUS.RESOLVED]: "resolved"
5557
+ };
5558
+ function malformed(field, value, context) {
5559
+ return new OrdersError(`Unknown ${field}: ${String(value)}`, {
5560
+ code: "MALFORMED_ORDER",
5561
+ context: { field, value, ...context }
5562
+ });
4400
5563
  }
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;
5564
+ function mapOrderType(v, ctx) {
5565
+ const t = ORDER_TYPE_MAP[v];
5566
+ return t ? ok5(t) : err4(malformed("orderType", v, ctx));
5567
+ }
5568
+ function mapOrderStatus(v, ctx) {
5569
+ const s = ORDER_STATUS_MAP[v];
5570
+ return s ? ok5(s) : err4(malformed("status", v, ctx));
5571
+ }
5572
+ function mapDisputeStatus(v, ctx) {
5573
+ const s = DISPUTE_STATUS_MAP[v];
5574
+ return s ? ok5(s) : err4(malformed("disputeStatus", v, ctx));
5575
+ }
5576
+ function decodeCurrency(hex) {
5577
+ return hexToString(hex, { size: 32 }).replaceAll("\0", "");
5578
+ }
5579
+ function normalizeContractOrder(raw, details) {
5580
+ if (raw.id === 0n && isAddressEqual(raw.user, zeroAddress)) return ok5(null);
5581
+ const ctx = { orderId: raw.id.toString() };
5582
+ return Result3.combine([
5583
+ mapOrderType(raw.orderType, ctx),
5584
+ mapOrderStatus(raw.status, ctx),
5585
+ mapDisputeStatus(raw.disputeInfo.status, ctx)
5586
+ ]).map(([type, status, disputeStatus]) => ({
5587
+ orderId: raw.id,
5588
+ type,
5589
+ status,
5590
+ usdcAmount: raw.amount,
5591
+ fiatAmount: raw.fiatAmount,
5592
+ actualUsdcAmount: details.actualUsdtAmount,
5593
+ actualFiatAmount: details.actualFiatAmount,
5594
+ currency: decodeCurrency(raw.currency),
5595
+ user: raw.user,
5596
+ recipient: raw.recipientAddr,
5597
+ acceptedMerchant: raw.acceptedMerchant,
5598
+ placedAt: raw.placedTimestamp,
5599
+ acceptedAt: details.acceptedTimestamp,
5600
+ paidAt: details.paidTimestamp,
5601
+ completedAt: raw.completedTimestamp,
5602
+ circleId: raw.circleId,
5603
+ fixedFeePaid: details.fixedFeePaid,
5604
+ tipsPaid: details.tipsPaid,
5605
+ disputeStatus,
5606
+ encUpi: raw.encUpi,
5607
+ encMerchantUpi: raw.encMerchantUpi,
5608
+ pubkey: raw.pubkey
5609
+ }));
4421
5610
  }
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
- });
5611
+ function normalizeSubgraphOrder(raw) {
5612
+ const ctx = { orderId: raw.orderId };
5613
+ return Result3.combine([
5614
+ mapOrderType(raw.type, ctx),
5615
+ mapOrderStatus(raw.status, ctx),
5616
+ mapDisputeStatus(raw.disputeStatus, ctx)
5617
+ ]).map(([type, status, disputeStatus]) => ({
5618
+ orderId: BigInt(raw.orderId),
5619
+ type,
5620
+ status,
5621
+ usdcAmount: BigInt(raw.usdcAmount),
5622
+ fiatAmount: BigInt(raw.fiatAmount),
5623
+ actualUsdcAmount: BigInt(raw.actualUsdcAmount),
5624
+ actualFiatAmount: BigInt(raw.actualFiatAmount),
5625
+ currency: decodeCurrency(raw.currency),
5626
+ user: raw.userAddress,
5627
+ recipient: raw.usdcRecipientAddress,
5628
+ acceptedMerchant: raw.acceptedMerchantAddress,
5629
+ placedAt: BigInt(raw.placedAt),
5630
+ acceptedAt: BigInt(raw.acceptedAt),
5631
+ paidAt: BigInt(raw.paidAt),
5632
+ completedAt: BigInt(raw.completedAt),
5633
+ circleId: BigInt(raw.circleId),
5634
+ fixedFeePaid: BigInt(raw.fixedFeePaid),
5635
+ tipsPaid: BigInt(raw.tipsPaid),
5636
+ disputeStatus,
5637
+ // Subgraph entity does not currently expose these encryption fields;
5638
+ // consumers needing them should fall back to the contract via getOrder.
5639
+ encUpi: "",
5640
+ encMerchantUpi: "",
5641
+ pubkey: ""
5642
+ }));
4459
5643
  }
4460
- var ZodEncryptedDataSchema = z7.object({
4461
- ciphertext: z7.string(),
4462
- iv: z7.string(),
4463
- mac: z7.string(),
4464
- ephemPublicKey: z7.string()
4465
- });
4466
5644
 
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
- });
5645
+ // src/orders/subgraph/index.ts
5646
+ import { Result as Result4 } from "neverthrow";
4486
5647
 
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
5648
+ // src/orders/subgraph/queries.ts
5649
+ var ORDERS_BY_USER_QUERY = (
5650
+ /* GraphQL */
5651
+ `
5652
+ query OrdersByUser($user: Bytes!, $skip: Int!, $first: Int!) {
5653
+ orders_collection(
5654
+ where: { userAddress: $user }
5655
+ orderBy: placedAt
5656
+ orderDirection: desc
5657
+ skip: $skip
5658
+ first: $first
5659
+ ) {
5660
+ orderId
5661
+ type
5662
+ status
5663
+ circleId
5664
+ userAddress
5665
+ usdcRecipientAddress
5666
+ acceptedMerchantAddress
5667
+ usdcAmount
5668
+ fiatAmount
5669
+ actualUsdcAmount
5670
+ actualFiatAmount
5671
+ currency
5672
+ placedAt
5673
+ acceptedAt
5674
+ paidAt
5675
+ completedAt
5676
+ fixedFeePaid
5677
+ tipsPaid
5678
+ disputeStatus
5679
+ }
5680
+ }
5681
+ `
5682
+ );
5683
+
5684
+ // src/orders/subgraph/index.ts
5685
+ function getOrdersForUser(subgraphUrl, userAddress, skip, limit, logger = noopLogger) {
5686
+ const user = userAddress.toLowerCase();
5687
+ logger.debug("fetching orders from subgraph", { subgraphUrl, user, skip, limit });
5688
+ return querySubgraph(subgraphUrl, {
5689
+ query: ORDERS_BY_USER_QUERY,
5690
+ variables: { user, skip, first: limit }
5691
+ }).mapErr(
5692
+ (e) => new OrdersError(e.message, {
5693
+ code: "SUBGRAPH_REQUEST_FAILED",
5694
+ cause: e.cause ?? e,
5695
+ context: { user, skip, limit, ...e.context ?? {} }
4531
5696
  })
5697
+ ).andThen(
5698
+ (data) => validate(
5699
+ ZodSubgraphOrdersResponseSchema,
5700
+ data,
5701
+ (message, cause, d) => new OrdersError(message, {
5702
+ code: "SUBGRAPH_VALIDATION_FAILED",
5703
+ cause,
5704
+ context: { data: d }
5705
+ })
5706
+ ).andThen(
5707
+ (validated) => Result4.combine(validated.orders_collection.map(normalizeSubgraphOrder))
5708
+ )
4532
5709
  );
4533
5710
  }
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
- }));
5711
+
5712
+ // src/orders/watch-events.ts
5713
+ var PLACED_CONFIG = {
5714
+ eventName: "OrderPlaced",
5715
+ toEvent: (log) => ({
5716
+ type: "placed",
5717
+ orderId: log.args.orderId,
5718
+ user: log.args.user,
5719
+ orderType: log.args.orderType,
5720
+ blockNumber: log.blockNumber,
5721
+ txHash: log.transactionHash
5722
+ }),
5723
+ userFromLog: (log) => log.args.user
5724
+ };
5725
+ var ACCEPTED_CONFIG = {
5726
+ eventName: "OrderAccepted",
5727
+ toEvent: (log) => ({
5728
+ type: "accepted",
5729
+ orderId: log.args.orderId,
5730
+ merchant: log.args.merchant,
5731
+ blockNumber: log.blockNumber,
5732
+ txHash: log.transactionHash
5733
+ }),
5734
+ // OrderAccepted's top-level args are (orderId, merchant, pubKey, _order).
5735
+ // The buyer's address lives inside the _order tuple as _order.user.
5736
+ userFromLog: (log) => log.args._order?.user
5737
+ };
5738
+ var PAID_CONFIG = {
5739
+ eventName: "BuyOrderPaid",
5740
+ toEvent: (log) => ({
5741
+ type: "paid",
5742
+ orderId: log.args.orderId,
5743
+ blockNumber: log.blockNumber,
5744
+ txHash: log.transactionHash
5745
+ }),
5746
+ userFromLog: (log) => log.args.user
5747
+ };
5748
+ var COMPLETED_CONFIG = {
5749
+ eventName: "OrderCompleted",
5750
+ toEvent: (log) => ({
5751
+ type: "completed",
5752
+ orderId: log.args.orderId,
5753
+ blockNumber: log.blockNumber,
5754
+ txHash: log.transactionHash
5755
+ }),
5756
+ userFromLog: (log) => log.args.user
5757
+ };
5758
+ var CANCELLED_CONFIG = {
5759
+ eventName: "CancelledOrders",
5760
+ toEvent: (log) => ({
5761
+ type: "cancelled",
5762
+ orderId: log.args.orderId,
5763
+ blockNumber: log.blockNumber,
5764
+ txHash: log.transactionHash
5765
+ }),
5766
+ // CancelledOrders's top-level args are (orderId, _order). The buyer's
5767
+ // address lives inside the _order tuple as _order.user.
5768
+ userFromLog: (log) => log.args._order?.user
5769
+ };
5770
+ var ALL_CONFIGS = [
5771
+ PLACED_CONFIG,
5772
+ ACCEPTED_CONFIG,
5773
+ PAID_CONFIG,
5774
+ COMPLETED_CONFIG,
5775
+ CANCELLED_CONFIG
5776
+ ];
5777
+ function createWatchEvents(input) {
5778
+ const { publicClient, diamondAddress } = input;
5779
+ return ({ user, onEvent, onError }) => {
5780
+ const unwatchers = [];
5781
+ for (const config of ALL_CONFIGS) {
5782
+ try {
5783
+ const unwatch = publicClient.watchContractEvent({
5784
+ address: diamondAddress,
5785
+ abi: ABIS.DIAMOND,
5786
+ eventName: config.eventName,
5787
+ onLogs: (logs) => {
5788
+ for (const log of logs) {
5789
+ if (user && config.userFromLog) {
5790
+ const logUser = config.userFromLog(log);
5791
+ if (!logUser || logUser.toLowerCase() !== user.toLowerCase()) continue;
5792
+ }
5793
+ onEvent(config.toEvent(log));
5794
+ }
5795
+ },
5796
+ onError: (err5) => {
5797
+ onError?.(
5798
+ new OrdersError(`watchContractEvent failed for ${config.eventName}`, {
5799
+ code: "EVENT_WATCH_FAILED",
5800
+ cause: err5,
5801
+ context: { eventName: config.eventName }
5802
+ })
5803
+ );
5804
+ }
5805
+ });
5806
+ unwatchers.push(unwatch);
5807
+ } catch (err5) {
5808
+ onError?.(
5809
+ new OrdersError(`failed to subscribe to ${config.eventName}`, {
5810
+ code: "EVENT_WATCH_FAILED",
5811
+ cause: err5,
5812
+ context: { eventName: config.eventName }
5813
+ })
5814
+ );
5815
+ }
5816
+ }
5817
+ return () => {
5818
+ for (const u of unwatchers) {
5819
+ try {
5820
+ u();
5821
+ } catch {
5822
+ }
5823
+ }
5824
+ };
5825
+ };
4549
5826
  }
4550
5827
 
4551
- // src/payload/client.ts
4552
- function createPayloadGenerator(config) {
5828
+ // src/orders/client.ts
5829
+ function createOrders(config) {
5830
+ const { publicClient, diamondAddress, usdcAddress, subgraphUrl, relayIdentity } = config;
5831
+ const logger = config.logger ?? noopLogger;
5832
+ const relayIdentityStore = config.relayIdentityStore ?? createInMemoryRelayStore();
5833
+ const orderRouter = createOrderRouter({
5834
+ publicClient,
5835
+ subgraphUrl,
5836
+ contractAddress: diamondAddress,
5837
+ logger
5838
+ });
4553
5839
  return {
4554
- placeOrder(params) {
4555
- return buildPlaceOrderPayload(config.orderRouter, params);
5840
+ // ── Reads ─────────────────────────────────────────────────────────
5841
+ getOrder(params) {
5842
+ return validate(
5843
+ ZodGetOrderParamsSchema,
5844
+ params,
5845
+ (message, cause, d) => new OrdersError(message, {
5846
+ code: "INVALID_ORDER_ID",
5847
+ cause,
5848
+ context: { params: d }
5849
+ })
5850
+ ).asyncAndThen(
5851
+ ({ orderId }) => readOrderMulticall(publicClient, diamondAddress, orderId).mapErr(
5852
+ (cause) => new OrdersError("Order contract read failed", {
5853
+ code: "CONTRACT_READ_FAILED",
5854
+ cause,
5855
+ context: { orderId: orderId.toString() }
5856
+ })
5857
+ )
5858
+ ).andThen(
5859
+ ({ order, details }) => normalizeContractOrder(order, details).asyncAndThen((normalized) => {
5860
+ if (!normalized) {
5861
+ return errAsync4(
5862
+ new OrdersError("Order not found", {
5863
+ code: "ORDER_NOT_FOUND",
5864
+ context: { orderId: params.orderId.toString() }
5865
+ })
5866
+ );
5867
+ }
5868
+ logger.debug("getOrder resolved", { orderId: params.orderId.toString() });
5869
+ return okAsync4(normalized);
5870
+ })
5871
+ );
5872
+ },
5873
+ getOrders(params) {
5874
+ return validate(
5875
+ ZodGetOrdersParamsSchema,
5876
+ params,
5877
+ (message, cause, d) => new OrdersError(message, {
5878
+ code: "INVALID_GET_ORDERS_PARAMS",
5879
+ cause,
5880
+ context: { params: d }
5881
+ })
5882
+ ).asyncAndThen(
5883
+ ({ userAddress, skip, limit }) => getOrdersForUser(subgraphUrl, userAddress, skip, limit, logger)
5884
+ );
5885
+ },
5886
+ getFeeConfig(params) {
5887
+ return validate(
5888
+ ZodGetFeeConfigParamsSchema,
5889
+ params,
5890
+ (message, cause, d) => new OrdersError(message, {
5891
+ code: "INVALID_FEE_CONFIG_PARAMS",
5892
+ cause,
5893
+ context: { params: d }
5894
+ })
5895
+ ).asyncAndThen(
5896
+ ({ currency }) => readFeeConfigMulticall(publicClient, diamondAddress, currency).mapErr(
5897
+ (cause) => new OrdersError("Fee config contract read failed", {
5898
+ code: "CONTRACT_READ_FAILED",
5899
+ cause,
5900
+ context: { currency }
5901
+ })
5902
+ )
5903
+ ).map((config2) => {
5904
+ logger.debug("getFeeConfig resolved", { currency: params.currency });
5905
+ return config2;
5906
+ });
5907
+ },
5908
+ // ── Writes ────────────────────────────────────────────────────────
5909
+ placeOrder: createPlaceOrderAction({
5910
+ publicClient,
5911
+ diamondAddress,
5912
+ orderRouter,
5913
+ relayIdentityStore,
5914
+ relayIdentity
5915
+ }),
5916
+ cancelOrder: createCancelOrderAction({ publicClient, diamondAddress }),
5917
+ setSellOrderUpi: createSetSellOrderUpiAction({
5918
+ publicClient,
5919
+ diamondAddress,
5920
+ relayIdentityStore,
5921
+ relayIdentity
5922
+ }),
5923
+ raiseDispute: createRaiseDisputeAction({ publicClient, diamondAddress }),
5924
+ approveUsdc: createApproveUsdcAction({ publicClient, diamondAddress, usdcAddress }),
5925
+ paidBuyOrder: createPaidBuyOrderAction({ publicClient, diamondAddress }),
5926
+ watchEvents: createWatchEvents({ publicClient, diamondAddress }),
5927
+ // ── Crypto helpers ───────────────────────────────────────────────
5928
+ decryptPaymentAddress({ encrypted }) {
5929
+ return resolveRelayIdentity({ relayIdentity, store: relayIdentityStore }).andThen(
5930
+ (recipientIdentity) => decryptPaymentAddress({ encrypted, recipientIdentity })
5931
+ );
4556
5932
  },
4557
- setSellOrderUpi(params) {
4558
- return buildSetSellOrderUpiPayload(params);
5933
+ encryptPaymentAddress({ paymentAddress, recipientPublicKey }) {
5934
+ return resolveRelayIdentity({ relayIdentity, store: relayIdentityStore }).andThen(
5935
+ (senderIdentity) => encryptPaymentAddress({
5936
+ paymentAddress,
5937
+ recipientPublicKey,
5938
+ senderIdentity
5939
+ })
5940
+ );
4559
5941
  }
4560
5942
  };
4561
5943
  }
4562
5944
 
5945
+ // src/prices/client.ts
5946
+ function createPrices(config) {
5947
+ const { publicClient, diamondAddress } = config;
5948
+ return {
5949
+ getPriceConfig: (params) => getPriceConfig(publicClient, diamondAddress, params),
5950
+ getReputationPerUsdcLimit: (params) => getReputationPerUsdcLimit(publicClient, diamondAddress, params)
5951
+ };
5952
+ }
5953
+
4563
5954
  // src/profile/contracts/actions.ts
4564
- import { ResultAsync as ResultAsync8 } from "neverthrow";
5955
+ import { ResultAsync as ResultAsync11 } from "neverthrow";
4565
5956
  import { formatUnits as formatUnits2 } from "viem";
4566
5957
  function getBalances(publicClient, usdcAddress, diamondAddress, params) {
4567
5958
  return validate(
@@ -4573,13 +5964,19 @@ function getBalances(publicClient, usdcAddress, diamondAddress, params) {
4573
5964
  context: { params: data }
4574
5965
  })
4575
5966
  ).asyncAndThen(
4576
- (validated) => ResultAsync8.combine([
5967
+ (validated) => ResultAsync11.combine([
4577
5968
  getUsdcBalance(publicClient, usdcAddress, {
4578
5969
  address: validated.address
4579
5970
  }),
4580
5971
  getPriceConfig(publicClient, diamondAddress, {
4581
5972
  currency: validated.currency
4582
- })
5973
+ }).mapErr(
5974
+ (cause) => new ProfileError("Failed to read price config for balance conversion", {
5975
+ code: "CONTRACT_READ_ERROR",
5976
+ cause,
5977
+ context: { currency: validated.currency }
5978
+ })
5979
+ )
4583
5980
  ]).map(([usdc, priceConfig]) => {
4584
5981
  const usdcFormatted = Number(formatUnits2(usdc, 6));
4585
5982
  const sellPriceFormatted = Number(formatUnits2(priceConfig.sellPrice, 6));
@@ -4597,10 +5994,9 @@ function createProfile(config) {
4597
5994
  const { publicClient, diamondAddress, usdcAddress } = config;
4598
5995
  return {
4599
5996
  getUsdcBalance: (params) => getUsdcBalance(publicClient, usdcAddress, params),
4600
- getPriceConfig: (params) => getPriceConfig(publicClient, diamondAddress, params),
5997
+ getUsdcAllowance: (params) => getUsdcAllowance(publicClient, usdcAddress, diamondAddress, params),
4601
5998
  getBalances: (params) => getBalances(publicClient, usdcAddress, diamondAddress, params),
4602
- getTxLimits: (params) => getTxLimits(publicClient, diamondAddress, params),
4603
- getRpPerUsdtLimitRational: (params) => getRpPerUsdtLimitRational(publicClient, diamondAddress, params)
5999
+ getTxLimits: (params) => getTxLimits(publicClient, diamondAddress, params)
4604
6000
  };
4605
6001
  }
4606
6002
 
@@ -4641,21 +6037,28 @@ function SdkProvider({ children, ...config }) {
4641
6037
  initedRef.current = fraudEngine;
4642
6038
  fraudEngine.init();
4643
6039
  }, [fraudEngine]);
6040
+ const relayIdentityStore = config.orders?.relayIdentityStore;
6041
+ const relayIdentity = config.orders?.relayIdentity;
4644
6042
  const sdk = useMemo(() => {
4645
- const orderRouter = createOrderRouter({
4646
- publicClient,
4647
- subgraphUrl: config.subgraphUrl,
4648
- contractAddress: config.diamondAddress,
4649
- logger
4650
- });
4651
6043
  return {
4652
6044
  profile: createProfile({
4653
6045
  publicClient,
4654
6046
  diamondAddress: config.diamondAddress,
4655
6047
  usdcAddress: config.usdcAddress
4656
6048
  }),
4657
- orderRouter,
4658
- payload: createPayloadGenerator({ orderRouter }),
6049
+ prices: createPrices({
6050
+ publicClient,
6051
+ diamondAddress: config.diamondAddress
6052
+ }),
6053
+ orders: createOrders({
6054
+ publicClient,
6055
+ diamondAddress: config.diamondAddress,
6056
+ usdcAddress: config.usdcAddress,
6057
+ subgraphUrl: config.subgraphUrl,
6058
+ relayIdentityStore,
6059
+ relayIdentity,
6060
+ logger
6061
+ }),
4659
6062
  zkkyc: config.reputationManagerAddress ? createZkkyc({
4660
6063
  reputationManagerAddress: config.reputationManagerAddress
4661
6064
  }) : void 0,
@@ -4667,6 +6070,8 @@ function SdkProvider({ children, ...config }) {
4667
6070
  config.diamondAddress,
4668
6071
  config.usdcAddress,
4669
6072
  config.reputationManagerAddress,
6073
+ relayIdentityStore,
6074
+ relayIdentity,
4670
6075
  logger,
4671
6076
  fraudEngine
4672
6077
  ]);
@@ -4682,11 +6087,11 @@ function useSdk() {
4682
6087
  function useProfile() {
4683
6088
  return useSdk().profile;
4684
6089
  }
4685
- function useOrderRouter() {
4686
- return useSdk().orderRouter;
6090
+ function usePrices() {
6091
+ return useSdk().prices;
4687
6092
  }
4688
- function usePayloadGenerator() {
4689
- return useSdk().payload;
6093
+ function useOrders() {
6094
+ return useSdk().orders;
4690
6095
  }
4691
6096
  function useZkkyc() {
4692
6097
  const zkkyc = useSdk().zkkyc;
@@ -4703,13 +6108,32 @@ function useFraudEngine() {
4703
6108
  return fraudEngine;
4704
6109
  }
4705
6110
 
6111
+ // src/react/use-watch-orders.ts
6112
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
6113
+ function useWatchOrders(params) {
6114
+ const orders = useOrders();
6115
+ const { user, onEvent, onError } = params;
6116
+ const onEventRef = useRef2(onEvent);
6117
+ const onErrorRef = useRef2(onError);
6118
+ onEventRef.current = onEvent;
6119
+ onErrorRef.current = onError;
6120
+ useEffect2(() => {
6121
+ const unsubscribe = orders.watchEvents({
6122
+ user,
6123
+ onEvent: (event) => onEventRef.current(event),
6124
+ onError: (error) => onErrorRef.current?.(error)
6125
+ });
6126
+ return unsubscribe;
6127
+ }, [orders, user]);
6128
+ }
6129
+
4706
6130
  // src/fraud-engine/react/use-fingerprint.ts
4707
- import { useEffect as useEffect2, useState } from "react";
6131
+ import { useEffect as useEffect3, useState } from "react";
4708
6132
  function useFingerprint(enabled) {
4709
6133
  const [data, setData] = useState(null);
4710
6134
  const [error, setError] = useState(null);
4711
6135
  const [isLoading, setIsLoading] = useState(false);
4712
- useEffect2(() => {
6136
+ useEffect3(() => {
4713
6137
  if (!enabled) return;
4714
6138
  let cancelled = false;
4715
6139
  setIsLoading(true);
@@ -4740,10 +6164,11 @@ export {
4740
6164
  SdkProvider,
4741
6165
  useFingerprint,
4742
6166
  useFraudEngine,
4743
- useOrderRouter,
4744
- usePayloadGenerator,
6167
+ useOrders,
6168
+ usePrices,
4745
6169
  useProfile,
4746
6170
  useSdk,
6171
+ useWatchOrders,
4747
6172
  useZkkyc
4748
6173
  };
4749
6174
  /*! Bundled license information: