@p2pdotme/sdk 1.0.5 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -41
- package/dist/country.cjs +9 -2
- package/dist/country.cjs.map +1 -1
- package/dist/country.d.cts +35 -10
- package/dist/country.d.ts +35 -10
- package/dist/country.mjs +6 -2
- package/dist/country.mjs.map +1 -1
- package/dist/fraud-engine.cjs +52 -48
- package/dist/fraud-engine.cjs.map +1 -1
- package/dist/fraud-engine.mjs +46 -42
- package/dist/fraud-engine.mjs.map +1 -1
- package/dist/index.cjs +4 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -36
- package/dist/index.d.ts +41 -36
- package/dist/index.mjs +4 -12
- package/dist/index.mjs.map +1 -1
- package/dist/orders.cjs +5961 -0
- package/dist/orders.cjs.map +1 -0
- package/dist/orders.d.cts +620 -0
- package/dist/orders.d.ts +620 -0
- package/dist/orders.mjs +5911 -0
- package/dist/orders.mjs.map +1 -0
- package/dist/prices.cjs +1432 -0
- package/dist/prices.cjs.map +1 -0
- package/dist/prices.d.cts +109 -0
- package/dist/prices.d.ts +109 -0
- package/dist/prices.mjs +1404 -0
- package/dist/prices.mjs.map +1 -0
- package/dist/profile.cjs +899 -69
- package/dist/profile.cjs.map +1 -1
- package/dist/profile.d.cts +39 -27
- package/dist/profile.d.ts +39 -27
- package/dist/profile.mjs +892 -62
- package/dist/profile.mjs.map +1 -1
- package/dist/qr-parsers.cjs +88 -7
- package/dist/qr-parsers.cjs.map +1 -1
- package/dist/qr-parsers.d.cts +38 -16
- package/dist/qr-parsers.d.ts +38 -16
- package/dist/qr-parsers.mjs +88 -7
- package/dist/qr-parsers.mjs.map +1 -1
- package/dist/react.cjs +2955 -1105
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +384 -104
- package/dist/react.d.ts +384 -104
- package/dist/react.mjs +2841 -992
- package/dist/react.mjs.map +1 -1
- package/dist/zkkyc.cjs +405 -24
- package/dist/zkkyc.cjs.map +1 -1
- package/dist/zkkyc.d.cts +14 -9
- package/dist/zkkyc.d.ts +14 -9
- package/dist/zkkyc.mjs +405 -24
- package/dist/zkkyc.mjs.map +1 -1
- package/package.json +12 -12
- package/dist/order-routing.cjs +0 -888
- package/dist/order-routing.cjs.map +0 -1
- package/dist/order-routing.d.cts +0 -68
- package/dist/order-routing.d.ts +0 -68
- package/dist/order-routing.mjs +0 -860
- package/dist/order-routing.mjs.map +0 -1
- package/dist/payload.cjs +0 -3168
- package/dist/payload.cjs.map +0 -1
- package/dist/payload.d.cts +0 -147
- package/dist/payload.d.ts +0 -147
- package/dist/payload.mjs +0 -3124
- 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/
|
|
39
|
-
|
|
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/
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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/
|
|
564
|
-
import {
|
|
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
|
-
|
|
608
|
-
|
|
609
|
-
|
|
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: "
|
|
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
|
-
|
|
618
|
-
|
|
619
|
-
|
|
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
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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
|
-
|
|
628
|
-
|
|
629
|
-
|
|
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
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
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
|
-
|
|
649
|
-
name: "
|
|
650
|
-
type: "
|
|
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
|
-
|
|
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
|
-
|
|
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 = [
|
|
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-
|
|
888
|
-
|
|
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/
|
|
891
|
-
|
|
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 = "
|
|
1423
|
+
this.name = "OrdersError";
|
|
895
1424
|
}
|
|
896
1425
|
};
|
|
897
1426
|
|
|
898
|
-
// src/
|
|
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
|
|
901
|
-
|
|
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
|
|
909
|
-
|
|
910
|
-
currency: z3.string(),
|
|
911
|
-
metrics: ZodCircleMetricsForRoutingSchema
|
|
1482
|
+
var ZodGetFeeConfigParamsSchema = z3.object({
|
|
1483
|
+
currency: ZodCurrencySchema
|
|
912
1484
|
});
|
|
913
|
-
var
|
|
914
|
-
|
|
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
|
|
917
|
-
|
|
918
|
-
currency:
|
|
1490
|
+
var ZodPlaceOrderParamsSchema = z3.object({
|
|
1491
|
+
orderType: z3.number().int().min(0).max(2),
|
|
1492
|
+
currency: ZodCurrencySchema,
|
|
919
1493
|
user: ZodAddressSchema,
|
|
920
|
-
|
|
1494
|
+
amount: z3.bigint(),
|
|
921
1495
|
fiatAmount: z3.bigint(),
|
|
922
|
-
|
|
923
|
-
|
|
1496
|
+
fiatAmountLimit: z3.bigint().optional().default(0n),
|
|
1497
|
+
recipientAddr: ZodAddressSchema,
|
|
1498
|
+
preferredPaymentChannelConfigId: z3.bigint().optional(),
|
|
1499
|
+
pubKey: z3.string().optional()
|
|
924
1500
|
});
|
|
925
|
-
var
|
|
926
|
-
|
|
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
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
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
|
|
997
|
-
|
|
998
|
-
|
|
1510
|
+
var ZodRaiseDisputeParamsSchema = z3.object({
|
|
1511
|
+
orderId: z3.bigint().nonnegative(),
|
|
1512
|
+
redactTransId: z3.bigint().nonnegative()
|
|
999
1513
|
});
|
|
1000
|
-
var
|
|
1001
|
-
|
|
1002
|
-
currency: ZodCurrencySchema
|
|
1514
|
+
var ZodApproveUsdcParamsSchema = z3.object({
|
|
1515
|
+
amount: z3.bigint().nonnegative()
|
|
1003
1516
|
});
|
|
1004
|
-
var
|
|
1005
|
-
|
|
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/
|
|
1009
|
-
function
|
|
1010
|
-
|
|
1011
|
-
|
|
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
|
|
1552
|
+
(message, cause, data) => new OrdersError(message, {
|
|
1014
1553
|
code: "VALIDATION_ERROR",
|
|
1015
1554
|
cause,
|
|
1016
|
-
context: {
|
|
1555
|
+
context: { data }
|
|
1017
1556
|
})
|
|
1018
|
-
).
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
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/
|
|
1036
|
-
import {
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
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
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
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
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
}
|
|
1107
|
-
|
|
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/
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
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
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
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
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
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
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
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
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
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
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
)
|
|
1190
|
-
(
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
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/
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
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
|
|
1257
|
-
|
|
1258
|
-
|
|
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
|
|
1797
|
+
(message, cause, data) => new OrdersError(message, {
|
|
1261
1798
|
code: "VALIDATION_ERROR",
|
|
1262
1799
|
cause,
|
|
1263
|
-
context: {
|
|
1800
|
+
context: { data }
|
|
1264
1801
|
})
|
|
1265
|
-
).asyncAndThen(
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
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
|
-
)
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
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/
|
|
1287
|
-
import {
|
|
1288
|
-
function
|
|
1289
|
-
|
|
1290
|
-
|
|
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
|
|
1875
|
+
(message, cause, data) => new OrdersError(message, {
|
|
1293
1876
|
code: "VALIDATION_ERROR",
|
|
1294
1877
|
cause,
|
|
1295
|
-
context: {
|
|
1878
|
+
context: { data }
|
|
1296
1879
|
})
|
|
1297
|
-
).
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
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
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
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/
|
|
1592
|
-
import {
|
|
1901
|
+
// src/orders/actions/set-sell-order-upi.ts
|
|
1902
|
+
import { encodeFunctionData as encodeFunctionData6 } from "viem";
|
|
1593
1903
|
|
|
1594
|
-
// src/
|
|
1595
|
-
import { ok as ok4, Result
|
|
1596
|
-
import { keccak256, serializeSignature, stringToHex as
|
|
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
|
|
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:
|
|
3548
|
-
if (Fp.eql(
|
|
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(
|
|
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(
|
|
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/
|
|
4626
|
+
// src/orders/crypto/ecies.ts
|
|
4627
|
+
var MIN_CIPHER_BYTES = 82;
|
|
4317
4628
|
function hexToBytes3(hex) {
|
|
4318
4629
|
const bytes = new Uint8Array(hex.length / 2);
|
|
4319
4630
|
for (let i = 0; i < bytes.length; i++) {
|
|
@@ -4326,242 +4637,1746 @@ function bytesToHex2(bytes) {
|
|
|
4326
4637
|
for (const b of bytes) {
|
|
4327
4638
|
hex += b.toString(16).padStart(2, "0");
|
|
4328
4639
|
}
|
|
4329
|
-
return hex;
|
|
4330
|
-
}
|
|
4331
|
-
function
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
}
|
|
4640
|
+
return hex;
|
|
4641
|
+
}
|
|
4642
|
+
function timingSafeEqual(a, b) {
|
|
4643
|
+
if (a.length !== b.length) return false;
|
|
4644
|
+
let diff = 0;
|
|
4645
|
+
for (let i = 0; i < a.length; i++) {
|
|
4646
|
+
diff |= a[i] ^ b[i];
|
|
4647
|
+
}
|
|
4648
|
+
return diff === 0;
|
|
4649
|
+
}
|
|
4650
|
+
function deriveKeys(sharedSecret) {
|
|
4651
|
+
const hash = sha5122(sharedSecret);
|
|
4652
|
+
return {
|
|
4653
|
+
encKey: hash.slice(0, 32),
|
|
4654
|
+
macKey: hash.slice(32)
|
|
4655
|
+
};
|
|
4656
|
+
}
|
|
4657
|
+
async function encryptWithPublicKey(publicKey, message) {
|
|
4658
|
+
const pubKeyBytes = hexToBytes3(`04${publicKey}`);
|
|
4659
|
+
const ephemPrivKey = randomBytes(32);
|
|
4660
|
+
const ephemPubKey = secp256k1.getPublicKey(ephemPrivKey, false);
|
|
4661
|
+
const sharedPoint = secp256k1.getSharedSecret(ephemPrivKey, pubKeyBytes, true);
|
|
4662
|
+
const sharedSecret = sharedPoint.slice(1);
|
|
4663
|
+
const { encKey, macKey } = deriveKeys(sharedSecret);
|
|
4664
|
+
const iv = randomBytes(16);
|
|
4665
|
+
const plaintext = new TextEncoder().encode(message);
|
|
4666
|
+
const cipher = cbc(encKey, iv);
|
|
4667
|
+
const ciphertext = cipher.encrypt(plaintext);
|
|
4668
|
+
const macData = concatBytes2(iv, ephemPubKey, ciphertext);
|
|
4669
|
+
const mac = hmac(sha2562, macKey, macData);
|
|
4670
|
+
return {
|
|
4671
|
+
iv: bytesToHex2(iv),
|
|
4672
|
+
ephemPublicKey: bytesToHex2(ephemPubKey),
|
|
4673
|
+
ciphertext: bytesToHex2(ciphertext),
|
|
4674
|
+
mac: bytesToHex2(mac)
|
|
4675
|
+
};
|
|
4676
|
+
}
|
|
4677
|
+
async function decryptWithPrivateKey(privateKey, encrypted) {
|
|
4678
|
+
const privKeyBytes = hexToBytes3(privateKey.replace(/^0x/, ""));
|
|
4679
|
+
const ephemPubKeyBytes = hexToBytes3(encrypted.ephemPublicKey);
|
|
4680
|
+
const ivBytes = hexToBytes3(encrypted.iv);
|
|
4681
|
+
const ciphertextBytes = hexToBytes3(encrypted.ciphertext);
|
|
4682
|
+
const macBytes = hexToBytes3(encrypted.mac);
|
|
4683
|
+
const sharedPoint = secp256k1.getSharedSecret(privKeyBytes, ephemPubKeyBytes, true);
|
|
4684
|
+
const sharedSecret = sharedPoint.slice(1);
|
|
4685
|
+
const { encKey, macKey } = deriveKeys(sharedSecret);
|
|
4686
|
+
const macData = concatBytes2(ivBytes, ephemPubKeyBytes, ciphertextBytes);
|
|
4687
|
+
const computedMac = hmac(sha2562, macKey, macData);
|
|
4688
|
+
if (!timingSafeEqual(computedMac, macBytes)) {
|
|
4689
|
+
throw new Error("MAC mismatch \u2014 ciphertext may be corrupted or tampered with");
|
|
4690
|
+
}
|
|
4691
|
+
const cipher = cbc(encKey, ivBytes);
|
|
4692
|
+
const plaintext = cipher.decrypt(ciphertextBytes);
|
|
4693
|
+
return new TextDecoder().decode(plaintext);
|
|
4694
|
+
}
|
|
4695
|
+
function cipherStringify(encrypted) {
|
|
4696
|
+
const ephemPubKeyBytes = hexToBytes3(encrypted.ephemPublicKey);
|
|
4697
|
+
const compressed = secp256k1.ProjectivePoint.fromHex(ephemPubKeyBytes).toRawBytes(true);
|
|
4698
|
+
const iv = hexToBytes3(encrypted.iv);
|
|
4699
|
+
const mac = hexToBytes3(encrypted.mac);
|
|
4700
|
+
const ciphertext = hexToBytes3(encrypted.ciphertext);
|
|
4701
|
+
return bytesToHex2(concatBytes2(iv, compressed, mac, ciphertext));
|
|
4702
|
+
}
|
|
4703
|
+
function cipherParse(str) {
|
|
4704
|
+
const buf = hexToBytes3(str);
|
|
4705
|
+
if (buf.length < MIN_CIPHER_BYTES) {
|
|
4706
|
+
throw new Error(
|
|
4707
|
+
`cipherParse: input too short (${buf.length} bytes, need at least ${MIN_CIPHER_BYTES})`
|
|
4708
|
+
);
|
|
4709
|
+
}
|
|
4710
|
+
const iv = buf.slice(0, 16);
|
|
4711
|
+
const compressed = buf.slice(16, 49);
|
|
4712
|
+
const mac = buf.slice(49, 81);
|
|
4713
|
+
const ciphertext = buf.slice(81);
|
|
4714
|
+
const ephemPubKey = secp256k1.ProjectivePoint.fromHex(compressed).toRawBytes(false);
|
|
4715
|
+
return {
|
|
4716
|
+
iv: bytesToHex2(iv),
|
|
4717
|
+
ephemPublicKey: bytesToHex2(ephemPubKey),
|
|
4718
|
+
ciphertext: bytesToHex2(ciphertext),
|
|
4719
|
+
mac: bytesToHex2(mac)
|
|
4720
|
+
};
|
|
4721
|
+
}
|
|
4722
|
+
|
|
4723
|
+
// src/orders/crypto/encryption.ts
|
|
4724
|
+
function tryParseLegacyEthCryptoEnvelope(input) {
|
|
4725
|
+
if (input.charCodeAt(0) !== 123) return void 0;
|
|
4726
|
+
let parsed;
|
|
4727
|
+
try {
|
|
4728
|
+
parsed = JSON.parse(input);
|
|
4729
|
+
} catch {
|
|
4730
|
+
return void 0;
|
|
4731
|
+
}
|
|
4732
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
4733
|
+
const o = parsed;
|
|
4734
|
+
if (typeof o.iv !== "string" || typeof o.ephemPublicKey !== "string" || typeof o.ciphertext !== "string" || typeof o.mac !== "string") {
|
|
4735
|
+
return void 0;
|
|
4736
|
+
}
|
|
4737
|
+
return {
|
|
4738
|
+
iv: o.iv,
|
|
4739
|
+
ephemPublicKey: o.ephemPublicKey,
|
|
4740
|
+
ciphertext: o.ciphertext,
|
|
4741
|
+
mac: o.mac
|
|
4742
|
+
};
|
|
4743
|
+
}
|
|
4744
|
+
function encryptPaymentAddress(input) {
|
|
4745
|
+
return safeTry(async function* () {
|
|
4746
|
+
const messageHash = keccak256(stringToHex3(input.paymentAddress));
|
|
4747
|
+
const signature = yield* ResultAsync6.fromPromise(
|
|
4748
|
+
sign({ hash: messageHash, privateKey: input.senderIdentity.privateKey }),
|
|
4749
|
+
(cause) => new OrdersError("Failed to sign payment address", {
|
|
4750
|
+
code: "ENCRYPTION_FAILED",
|
|
4751
|
+
cause
|
|
4752
|
+
})
|
|
4753
|
+
).map(serializeSignature);
|
|
4754
|
+
const payload = JSON.stringify({ message: input.paymentAddress, signature });
|
|
4755
|
+
const encrypted = yield* ResultAsync6.fromPromise(
|
|
4756
|
+
encryptWithPublicKey(input.recipientPublicKey, payload),
|
|
4757
|
+
(cause) => new OrdersError("ECIES encryption failed", {
|
|
4758
|
+
code: "ENCRYPTION_FAILED",
|
|
4759
|
+
cause
|
|
4760
|
+
})
|
|
4761
|
+
);
|
|
4762
|
+
const safeStringify = Result.fromThrowable(
|
|
4763
|
+
(e) => cipherStringify(e),
|
|
4764
|
+
(cause) => new OrdersError("Ciphertext stringify failed", {
|
|
4765
|
+
code: "ENCRYPTION_FAILED",
|
|
4766
|
+
cause
|
|
4767
|
+
})
|
|
4768
|
+
);
|
|
4769
|
+
return ok4(yield* safeStringify(encrypted));
|
|
4770
|
+
});
|
|
4771
|
+
}
|
|
4772
|
+
var ZodDecryptedPayloadSchema = z5.object({
|
|
4773
|
+
message: z5.string(),
|
|
4774
|
+
signature: z5.string()
|
|
4775
|
+
});
|
|
4776
|
+
function decryptPaymentAddress(input) {
|
|
4777
|
+
return safeTry(async function* () {
|
|
4778
|
+
const legacyEnvelope = tryParseLegacyEthCryptoEnvelope(input.encrypted);
|
|
4779
|
+
const safeCipherParse = Result.fromThrowable(
|
|
4780
|
+
(s) => cipherParse(s),
|
|
4781
|
+
(cause) => new OrdersError("Failed to parse ciphertext", {
|
|
4782
|
+
code: "ENCRYPTION_FAILED",
|
|
4783
|
+
cause
|
|
4784
|
+
})
|
|
4785
|
+
);
|
|
4786
|
+
const encryptedData = legacyEnvelope ?? (yield* safeCipherParse(input.encrypted));
|
|
4787
|
+
const plaintext = yield* ResultAsync6.fromPromise(
|
|
4788
|
+
decryptWithPrivateKey(input.recipientIdentity.privateKey, encryptedData),
|
|
4789
|
+
(cause) => new OrdersError("ECIES decryption failed", {
|
|
4790
|
+
code: "ENCRYPTION_FAILED",
|
|
4791
|
+
cause
|
|
4792
|
+
})
|
|
4793
|
+
);
|
|
4794
|
+
if (legacyEnvelope) {
|
|
4795
|
+
return ok4(plaintext);
|
|
4796
|
+
}
|
|
4797
|
+
const safeJsonParse = Result.fromThrowable(
|
|
4798
|
+
(s) => JSON.parse(s),
|
|
4799
|
+
(cause) => new OrdersError("Failed to parse decrypted payload JSON", {
|
|
4800
|
+
code: "ENCRYPTION_FAILED",
|
|
4801
|
+
cause
|
|
4802
|
+
})
|
|
4803
|
+
);
|
|
4804
|
+
const parsed = yield* safeJsonParse(plaintext);
|
|
4805
|
+
const payload = yield* validate(
|
|
4806
|
+
ZodDecryptedPayloadSchema,
|
|
4807
|
+
parsed,
|
|
4808
|
+
(message, cause, data) => new OrdersError(message, {
|
|
4809
|
+
code: "ENCRYPTION_FAILED",
|
|
4810
|
+
cause,
|
|
4811
|
+
context: { data }
|
|
4812
|
+
})
|
|
4813
|
+
);
|
|
4814
|
+
return ok4(payload.message);
|
|
4815
|
+
});
|
|
4816
|
+
}
|
|
4817
|
+
|
|
4818
|
+
// src/orders/actions/set-sell-order-upi.ts
|
|
4819
|
+
function createSetSellOrderUpiAction(input) {
|
|
4820
|
+
const { publicClient, diamondAddress, relayIdentityStore, relayIdentity } = input;
|
|
4821
|
+
const prepareFn = (params) => validate(
|
|
4822
|
+
ZodSetSellOrderUpiParamsSchema,
|
|
4823
|
+
params,
|
|
4824
|
+
(message, cause, data) => new OrdersError(message, {
|
|
4825
|
+
code: "VALIDATION_ERROR",
|
|
4826
|
+
cause,
|
|
4827
|
+
context: { data }
|
|
4828
|
+
})
|
|
4829
|
+
).asyncAndThen(
|
|
4830
|
+
(v) => resolveRelayIdentity({ relayIdentity, store: relayIdentityStore }).andThen(
|
|
4831
|
+
(senderIdentity) => encryptPaymentAddress({
|
|
4832
|
+
paymentAddress: v.paymentAddress,
|
|
4833
|
+
recipientPublicKey: v.merchantPublicKey,
|
|
4834
|
+
senderIdentity
|
|
4835
|
+
}).map((userEncUpi) => ({ v, userEncUpi, senderIdentity }))
|
|
4836
|
+
)
|
|
4837
|
+
).map(({ v, userEncUpi, senderIdentity }) => ({
|
|
4838
|
+
to: diamondAddress,
|
|
4839
|
+
data: encodeFunctionData6({
|
|
4840
|
+
abi: ABIS.FACETS.ORDER_FLOW,
|
|
4841
|
+
functionName: "setSellOrderUpi",
|
|
4842
|
+
args: [v.orderId, userEncUpi, v.updatedAmount]
|
|
4843
|
+
}),
|
|
4844
|
+
value: 0n,
|
|
4845
|
+
meta: { relayIdentity: senderIdentity }
|
|
4846
|
+
}));
|
|
4847
|
+
return {
|
|
4848
|
+
prepare(params) {
|
|
4849
|
+
return prepareFn(params);
|
|
4850
|
+
},
|
|
4851
|
+
execute({ walletClient, waitForReceipt, ...params }) {
|
|
4852
|
+
return prepareFn(params).andThen(
|
|
4853
|
+
(prepared) => submitPreparedTx({ prepared, walletClient, publicClient, waitForReceipt })
|
|
4854
|
+
);
|
|
4855
|
+
}
|
|
4856
|
+
};
|
|
4857
|
+
}
|
|
4858
|
+
|
|
4859
|
+
// src/orders/internal/routing/client.ts
|
|
4860
|
+
import { stringToHex as stringToHex6 } from "viem";
|
|
4861
|
+
|
|
4862
|
+
// src/contracts/errors.ts
|
|
4863
|
+
var contractErrors = {
|
|
4864
|
+
// Access control
|
|
4865
|
+
NotAdmin: "NOT_ADMIN",
|
|
4866
|
+
NotSuperAdmin: "NOT_SUPER_ADMIN",
|
|
4867
|
+
NotAuthorized: "NOT_AUTHORIZED",
|
|
4868
|
+
NotSelf: "NOT_SELF",
|
|
4869
|
+
NotWhitelisted: "NOT_WHITELISTED",
|
|
4870
|
+
NotCircleAdmin: "NOT_CIRCLE_ADMIN",
|
|
4871
|
+
// Circle / community management
|
|
4872
|
+
InvalidName: "INVALID_NAME",
|
|
4873
|
+
InvalidCommunityUrl: "INVALID_COMMUNITY_URL",
|
|
4874
|
+
InvalidAdminCommunityUrl: "INVALID_ADMIN_COMMUNITY_URL",
|
|
4875
|
+
AdminAlreadyHasCircle: "ADMIN_ALREADY_HAS_CIRCLE",
|
|
4876
|
+
CircleNameAlreadyTaken: "CIRCLE_NAME_ALREADY_TAKEN",
|
|
4877
|
+
P2PStakeConfigNotSet: "P2P_STAKE_CONFIG_NOT_SET",
|
|
4878
|
+
InsufficientP2PStake: "INSUFFICIENT_P2P_STAKE",
|
|
4879
|
+
P2PTokenNotSet: "P2P_TOKEN_NOT_SET",
|
|
4880
|
+
P2PUnstakeRequestPending: "P2P_UNSTAKE_REQUEST_PENDING",
|
|
4881
|
+
NoP2PUnstakeRequest: "NO_P2P_UNSTAKE_REQUEST",
|
|
4882
|
+
P2PUnstakeCooldownNotPassed: "P2P_UNSTAKE_COOLDOWN_NOT_PASSED",
|
|
4883
|
+
SlashAmountExceedsStake: "SLASH_AMOUNT_EXCEEDS_STAKE",
|
|
4884
|
+
CircleNotActive: "CIRCLE_NOT_ACTIVE",
|
|
4885
|
+
InvalidCircleId: "INVALID_CIRCLE_ID",
|
|
4886
|
+
CurrencyMismatch: "CURRENCY_MISMATCH",
|
|
4887
|
+
CircleFull: "CIRCLE_FULL",
|
|
4888
|
+
CircleIdMismatch: "CIRCLE_ID_MISMATCH",
|
|
4889
|
+
DuplicateAccountName: "DUPLICATE_ACCOUNT_NAME",
|
|
4890
|
+
EmptyName: "EMPTY_NAME",
|
|
4891
|
+
AccountBoundToAnotherCircle: "ACCOUNT_BOUND_TO_ANOTHER_CIRCLE",
|
|
4892
|
+
ExitAmountExceededCircleBalance: "EXIT_AMOUNT_EXCEEDED_CIRCLE_BALANCE",
|
|
4893
|
+
UndelegationAmountTooHigh: "UNDELEGATION_AMOUNT_TOO_HIGH",
|
|
4894
|
+
// Exchange / order lifecycle
|
|
4895
|
+
ExchangeNotOperational: "EXCHANGE_NOT_OPERATIONAL",
|
|
4896
|
+
OrderNotPlaced: "ORDER_NOT_PLACED",
|
|
4897
|
+
OrderNotPaid: "ORDER_NOT_PAID",
|
|
4898
|
+
OrderStatusInvalid: "ORDER_STATUS_INVALID",
|
|
4899
|
+
OrderExpired: "ORDER_EXPIRED",
|
|
4900
|
+
OrderAlreadyPaid: "ORDER_ALREADY_PAID",
|
|
4901
|
+
OrderAlreadyCompleted: "ORDER_ALREADY_COMPLETED",
|
|
4902
|
+
InvalidOrderType: "INVALID_ORDER_TYPE",
|
|
4903
|
+
OrderTypeIncorrect: "ORDER_TYPE_INCORRECT",
|
|
4904
|
+
OrderNotAccepted: "ORDER_NOT_ACCEPTED",
|
|
4905
|
+
OrderNotAssigned: "ORDER_NOT_ASSIGNED",
|
|
4906
|
+
OrderAmountExceedsLimit: "ORDER_AMOUNT_EXCEEDS_LIMIT",
|
|
4907
|
+
InvalidOrderAmount: "INVALID_ORDER_AMOUNT",
|
|
4908
|
+
InvalidOrderAmountToCoverFee: "INVALID_ORDER_AMOUNT_TO_COVER_FEE",
|
|
4909
|
+
InvalidOrderId: "INVALID_ORDER_ID",
|
|
4910
|
+
OrderTooEarlyForReassignment: "ORDER_TOO_EARLY_FOR_REASSIGNMENT",
|
|
4911
|
+
OrderTooLateForReassignment: "ORDER_TOO_LATE_FOR_REASSIGNMENT",
|
|
4912
|
+
ReAssignmentNotRequired: "REASSIGNMENT_NOT_REQUIRED",
|
|
4913
|
+
TipAlreadyGiven: "TIP_ALREADY_GIVEN",
|
|
4914
|
+
CashbackTransferFailed: "CASHBACK_TRANSFER_FAILED",
|
|
4915
|
+
// Order limits
|
|
4916
|
+
DailyBuyOrderLimitExceeded: "DAILY_BUY_ORDER_LIMIT_EXCEEDED",
|
|
4917
|
+
MonthlyBuyOrderLimitExceeded: "MONTHLY_BUY_ORDER_LIMIT_EXCEEDED",
|
|
4918
|
+
SellOrderAmountLimitExceeded: "SELL_ORDER_AMOUNT_LIMIT_EXCEEDED",
|
|
4919
|
+
BuyOrderAmountExceedsLimit: "BUY_ORDER_AMOUNT_EXCEEDS_LIMIT",
|
|
4920
|
+
SellOrderAmountExceedsLimit: "SELL_ORDER_AMOUNT_EXCEEDS_LIMIT",
|
|
4921
|
+
BuyAmountExceedsUsdcLimit: "BUY_AMOUNT_EXCEEDS_USDC_LIMIT",
|
|
4922
|
+
SellAmountExceedsFiatLimit: "SELL_AMOUNT_EXCEEDS_FIAT_LIMIT",
|
|
4923
|
+
DailyVolumeLimitExceeded: "DAILY_VOLUME_LIMIT_EXCEEDED",
|
|
4924
|
+
MonthlyVolumeLimitExceeded: "MONTHLY_VOLUME_LIMIT_EXCEEDED",
|
|
4925
|
+
UserYearlyVolumeLimitExceeded: "USER_YEARLY_VOLUME_LIMIT_EXCEEDED",
|
|
4926
|
+
// Dispute
|
|
4927
|
+
DisputeTimeNotReached: "DISPUTE_TIME_NOT_REACHED",
|
|
4928
|
+
DisputeTimeExpired: "DISPUTE_TIME_EXPIRED",
|
|
4929
|
+
InvalidOrderStatusToRaiseDispute: "INVALID_ORDER_STATUS_TO_RAISE_DISPUTE",
|
|
4930
|
+
DisputeNotRaised: "DISPUTE_NOT_RAISED",
|
|
4931
|
+
CannotRaiseDisputeTwice: "CANNOT_RAISE_DISPUTE_TWICE",
|
|
4932
|
+
DisputeAlreadySettled: "DISPUTE_ALREADY_SETTLED",
|
|
4933
|
+
TransactionIdMismatch: "TRANSACTION_ID_MISMATCH",
|
|
4934
|
+
AccountNumberMismatch: "ACCOUNT_NUMBER_MISMATCH",
|
|
4935
|
+
NotPaidBuyOrder: "NOT_PAID_BUY_ORDER",
|
|
4936
|
+
// Payment channels
|
|
4937
|
+
PaymentChannelNotFound: "PAYMENT_CHANNEL_NOT_FOUND",
|
|
4938
|
+
PaymentChannelNotActive: "PAYMENT_CHANNEL_NOT_ACTIVE",
|
|
4939
|
+
PaymentChannelNotApproved: "PAYMENT_CHANNEL_NOT_APPROVED",
|
|
4940
|
+
PaymentChannelNotRejected: "PAYMENT_CHANNEL_NOT_REJECTED",
|
|
4941
|
+
InvalidPaymentChannelId: "INVALID_PAYMENT_CHANNEL_ID",
|
|
4942
|
+
DuplicatePaymentChannel: "DUPLICATE_PAYMENT_CHANNEL",
|
|
4943
|
+
OldPaymentChannelNotFound: "OLD_PAYMENT_CHANNEL_NOT_FOUND",
|
|
4944
|
+
NewPaymentChannelNotFound: "NEW_PAYMENT_CHANNEL_NOT_FOUND",
|
|
4945
|
+
SamePaymentChannel: "SAME_PAYMENT_CHANNEL",
|
|
4946
|
+
OldPaymentChannelShouldBeInactive: "OLD_PAYMENT_CHANNEL_SHOULD_BE_INACTIVE",
|
|
4947
|
+
NewPaymentChannelShouldBeActive: "NEW_PAYMENT_CHANNEL_SHOULD_BE_ACTIVE",
|
|
4948
|
+
OngoingOrderOnPaymentChannel: "ONGOING_ORDER_ON_PAYMENT_CHANNEL",
|
|
4949
|
+
UpiAlreadySent: "UPI_ALREADY_SENT",
|
|
4950
|
+
InvalidOrderUpi: "INVALID_ORDER_UPI",
|
|
4951
|
+
NoFiatLiquidity: "NO_FIAT_LIQUIDITY",
|
|
4952
|
+
// Merchant
|
|
4953
|
+
NotEnoughEligibleMerchants: "NOT_ENOUGH_ELIGIBLE_MERCHANTS",
|
|
4954
|
+
MerchantNotRegistered: "MERCHANT_NOT_REGISTERED",
|
|
4955
|
+
MerchantNotApproved: "MERCHANT_NOT_APPROVED",
|
|
4956
|
+
MerchantAlreadyRegistered: "MERCHANT_ALREADY_REGISTERED",
|
|
4957
|
+
MerchantAlreadyRejected: "MERCHANT_ALREADY_REJECTED",
|
|
4958
|
+
MerchantBlacklisted: "MERCHANT_BLACKLISTED",
|
|
4959
|
+
MerchantNotBlacklisted: "MERCHANT_NOT_BLACKLISTED",
|
|
4960
|
+
MerchantAlreadyBlacklisted: "MERCHANT_ALREADY_BLACKLISTED",
|
|
4961
|
+
MerchantHasOngoingOrders: "MERCHANT_HAS_ONGOING_ORDERS",
|
|
4962
|
+
MerchantNotFullfilledEligibilityThreshold: "MERCHANT_NOT_FULLFILLED_ELIGIBILITY_THRESHOLD",
|
|
4963
|
+
InvalidMerchant: "INVALID_MERCHANT",
|
|
4964
|
+
// Staking / unstaking
|
|
4965
|
+
StakeAmountTooLow: "STAKE_AMOUNT_TOO_LOW",
|
|
4966
|
+
AdditionalStakeNotAllowed: "ADDITIONAL_STAKE_NOT_ALLOWED",
|
|
4967
|
+
UnstakeRequestPending: "UNSTAKE_REQUEST_PENDING",
|
|
4968
|
+
UnstakeRequestNotPending: "UNSTAKE_REQUEST_NOT_PENDING",
|
|
4969
|
+
UnstakeAmountExceeded: "UNSTAKE_AMOUNT_EXCEEDED",
|
|
4970
|
+
ZeroUnstakeAmount: "ZERO_UNSTAKE_AMOUNT",
|
|
4971
|
+
NoWithdrawableAmount: "NO_WITHDRAWABLE_AMOUNT",
|
|
4972
|
+
NoStake: "NO_STAKE",
|
|
4973
|
+
NoStakers: "NO_STAKERS",
|
|
4974
|
+
InsufficientStakedAmount: "INSUFFICIENT_STAKED_AMOUNT",
|
|
4975
|
+
CooldownNotPassed: "COOLDOWN_NOT_PASSED",
|
|
4976
|
+
ClaimableRewardsNotAvailable: "CLAIMABLE_REWARDS_NOT_AVAILABLE",
|
|
4977
|
+
// Delegation
|
|
4978
|
+
ExitWouldBreachDelegationInvariant: "EXIT_WOULD_BREACH_DELEGATION_INVARIANT",
|
|
4979
|
+
AggregateDelegationExceedsTotalStaked: "AGGREGATE_DELEGATION_EXCEEDS_TOTAL_STAKED",
|
|
4980
|
+
InsufficientMerchantRewards: "INSUFFICIENT_MERCHANT_REWARDS",
|
|
4981
|
+
// Migration
|
|
4982
|
+
InvalidMigrationStatus: "INVALID_MIGRATION_STATUS",
|
|
4983
|
+
MigrationRequestNotPending: "MIGRATION_REQUEST_NOT_PENDING",
|
|
4984
|
+
MigrationAlreadyRequested: "MIGRATION_ALREADY_REQUESTED",
|
|
4985
|
+
// Token / currency
|
|
4986
|
+
TokenAlreadyExists: "TOKEN_ALREADY_EXISTS",
|
|
4987
|
+
TokenNotFound: "TOKEN_NOT_FOUND",
|
|
4988
|
+
TokenEmpty: "TOKEN_EMPTY",
|
|
4989
|
+
CurrencyNotSupported: "CURRENCY_NOT_SUPPORTED",
|
|
4990
|
+
InvalidCurrency: "INVALID_CURRENCY",
|
|
4991
|
+
// USDC / transfer
|
|
4992
|
+
UsdtTransferFailed: "USDC_TRANSFER_FAILED",
|
|
4993
|
+
UsdtTransferFailedWithErrorMessage: "USDC_TRANSFER_FAILED_WITH_ERROR_MESSAGE",
|
|
4994
|
+
UsdtTransferFailedWithPanic: "USDC_TRANSFER_FAILED_WITH_PANIC",
|
|
4995
|
+
InsufficientAllowance: "INSUFFICIENT_ALLOWANCE",
|
|
4996
|
+
// ZK Passport
|
|
4997
|
+
ZKPassportVerifierNotSet: "ZK_PASSPORT_VERIFIER_NOT_SET",
|
|
4998
|
+
ZKPassportDomainEmpty: "ZK_PASSPORT_DOMAIN_EMPTY",
|
|
4999
|
+
ZKPassportScopeEmpty: "ZK_PASSPORT_SCOPE_EMPTY",
|
|
5000
|
+
PassportAlreadyVerified: "PASSPORT_ALREADY_VERIFIED",
|
|
5001
|
+
ZKPassportProofInvalid: "ZK_PASSPORT_PROOF_INVALID",
|
|
5002
|
+
ZKPassportIdentifierAlreadyVerified: "ZK_PASSPORT_IDENTIFIER_ALREADY_VERIFIED",
|
|
5003
|
+
ZKPassportInvalidScope: "ZK_PASSPORT_INVALID_SCOPE",
|
|
5004
|
+
ZKPassportUnexpectedSender: "ZK_PASSPORT_UNEXPECTED_SENDER",
|
|
5005
|
+
ZKPassportAgeBelowMinimum: "ZK_PASSPORT_AGE_BELOW_MINIMUM",
|
|
5006
|
+
ZKPassportMinAgeTooHigh: "ZK_PASSPORT_MIN_AGE_TOO_HIGH",
|
|
5007
|
+
// Chainlink / oracle
|
|
5008
|
+
UnexpectedRequestId: "UNEXPECTED_REQUEST_ID",
|
|
5009
|
+
OnlyRouterCanFulfill: "ONLY_ROUTER_CAN_FULFILL",
|
|
5010
|
+
RequestFailed: "REQUEST_FAILED",
|
|
5011
|
+
SourceCodeMismatch: "SOURCE_CODE_MISMATCH",
|
|
5012
|
+
ZeroMarketPrice: "ZERO_MARKET_PRICE",
|
|
5013
|
+
InvalidComputedPrices: "INVALID_COMPUTED_PRICES",
|
|
5014
|
+
NotPriceUpdaterForCurrency: "NOT_PRICE_UPDATER_FOR_CURRENCY",
|
|
5015
|
+
ThresholdNotConfigured: "THRESHOLD_NOT_CONFIGURED",
|
|
5016
|
+
SlippageExceeded: "SLIPPAGE_EXCEEDED",
|
|
5017
|
+
// Reputation / verification
|
|
5018
|
+
UserHasNoReputation: "USER_HAS_NO_REPUTATION",
|
|
5019
|
+
ZeroReputationPoints: "ZERO_REPUTATION_POINTS",
|
|
5020
|
+
NoReputation: "NO_REPUTATION",
|
|
5021
|
+
InsufficientRP: "INSUFFICIENT_RP",
|
|
5022
|
+
NullifierAlreadyVerified: "NULLIFIER_ALREADY_VERIFIED",
|
|
5023
|
+
VerificationFailed: "VERIFICATION_FAILED",
|
|
5024
|
+
InvalidSocialPlatform: "INVALID_SOCIAL_PLATFORM",
|
|
5025
|
+
SocialAlreadyVerified: "SOCIAL_ALREADY_VERIFIED",
|
|
5026
|
+
YearFieldNotInProof: "YEAR_FIELD_NOT_IN_PROOF",
|
|
5027
|
+
UserIdFieldNotInProof: "USER_ID_FIELD_NOT_IN_PROOF",
|
|
5028
|
+
UserIdAlreadyVerified: "USER_ID_ALREADY_VERIFIED",
|
|
5029
|
+
UsernameAlreadyVerified: "USERNAME_ALREADY_VERIFIED",
|
|
5030
|
+
UsernameNotInProof: "USERNAME_NOT_IN_PROOF",
|
|
5031
|
+
LinkedInOnlyRpUpdates: "LINKEDIN_ONLY_RP_UPDATES",
|
|
5032
|
+
FacebookOnlyRpUpdates: "FACEBOOK_ONLY_RP_UPDATES",
|
|
5033
|
+
// Voting / referral
|
|
5034
|
+
AlreadyReferred: "ALREADY_REFERRED",
|
|
5035
|
+
SelfReferralNotAllowed: "SELF_REFERRAL_NOT_ALLOWED",
|
|
5036
|
+
NotEligibleToRefer: "NOT_ELIGIBLE_TO_REFER",
|
|
5037
|
+
MerchantMonthlyReferralLimitReached: "MERCHANT_MONTHLY_REFERRAL_LIMIT_REACHED",
|
|
5038
|
+
NoRecommender: "NO_RECOMMENDER",
|
|
5039
|
+
RecommendationAlreadyClaimed: "RECOMMENDATION_ALREADY_CLAIMED",
|
|
5040
|
+
CannotVoteYourself: "CANNOT_VOTE_YOURSELF",
|
|
5041
|
+
VotesPerEpochExceeded: "VOTES_PER_EPOCH_EXCEEDED",
|
|
5042
|
+
AlreadyVoted: "ALREADY_VOTED",
|
|
5043
|
+
FunctionNotFound: "FUNCTION_NOT_FOUND",
|
|
5044
|
+
// Campaign
|
|
5045
|
+
CampaignNotActive: "CAMPAIGN_NOT_ACTIVE",
|
|
5046
|
+
InvalidManagerDetails: "INVALID_MANAGER_DETAILS",
|
|
5047
|
+
UnclaimedRewardsExist: "UNCLAIMED_REWARDS_EXIST",
|
|
5048
|
+
RewardAlreadyClaimed: "REWARD_ALREADY_CLAIMED",
|
|
5049
|
+
OnlyNewUsersAllowed: "ONLY_NEW_USERS_ALLOWED",
|
|
5050
|
+
ManagerNotFound: "MANAGER_NOT_FOUND",
|
|
5051
|
+
ManagerInactive: "MANAGER_INACTIVE",
|
|
5052
|
+
NoRewards: "NO_REWARDS",
|
|
5053
|
+
InvalidCampaignId: "INVALID_CAMPAIGN_ID",
|
|
5054
|
+
CannotClaimRevenueForCurrentMonth: "CANNOT_CLAIM_REVENUE_FOR_CURRENT_MONTH",
|
|
5055
|
+
// Referral reward config
|
|
5056
|
+
RewardPercentageTooHigh: "REWARD_PERCENTAGE_TOO_HIGH",
|
|
5057
|
+
// Signature / nonce
|
|
5058
|
+
NonceAlreadyUsed: "NONCE_ALREADY_USED",
|
|
5059
|
+
SignatureValidationFailed: "SIGNATURE_VALIDATION_FAILED",
|
|
5060
|
+
// Misc
|
|
5061
|
+
InvalidAddress: "INVALID_ADDRESS",
|
|
5062
|
+
InvalidBlockAmount: "INVALID_BLOCK_AMOUNT",
|
|
5063
|
+
InvalidAmount: "INVALID_AMOUNT",
|
|
5064
|
+
InvalidInput: "INVALID_INPUT",
|
|
5065
|
+
InvalidStatusTransition: "INVALID_STATUS_TRANSITION",
|
|
5066
|
+
ArrayLengthMismatch: "ARRAY_LENGTH_MISMATCH",
|
|
5067
|
+
UserIsBlacklisted: "USER_IS_BLACKLISTED",
|
|
5068
|
+
ZeroAddress: "ZERO_ADDRESS",
|
|
5069
|
+
ReentrancyGuard: "REENTRANCY_GUARD",
|
|
5070
|
+
BatchTooLarge: "BATCH_TOO_LARGE",
|
|
5071
|
+
UnderflowSubtraction: "UNDERFLOW_SUBTRACTION",
|
|
5072
|
+
TargetLongerThanData: "TARGET_LONGER_THAN_DATA"
|
|
5073
|
+
};
|
|
5074
|
+
var hexContractErrors = {
|
|
5075
|
+
// Access control
|
|
5076
|
+
"0x7bfa4b9f": contractErrors.NotAdmin,
|
|
5077
|
+
"0x16c726b1": contractErrors.NotSuperAdmin,
|
|
5078
|
+
"0xea8e4eb5": contractErrors.NotAuthorized,
|
|
5079
|
+
"0x29c3b7ee": contractErrors.NotSelf,
|
|
5080
|
+
"0x584a7938": contractErrors.NotWhitelisted,
|
|
5081
|
+
"0xa8143fbc": contractErrors.NotCircleAdmin,
|
|
5082
|
+
// Circle / community management
|
|
5083
|
+
"0x430f13b3": contractErrors.InvalidName,
|
|
5084
|
+
"0xe7cbf75a": contractErrors.InvalidCommunityUrl,
|
|
5085
|
+
"0x3762bfee": contractErrors.InvalidAdminCommunityUrl,
|
|
5086
|
+
"0x201c1ffc": contractErrors.AdminAlreadyHasCircle,
|
|
5087
|
+
"0x6540a51d": contractErrors.CircleNameAlreadyTaken,
|
|
5088
|
+
"0xcadc6786": contractErrors.P2PStakeConfigNotSet,
|
|
5089
|
+
"0x78317f44": contractErrors.InsufficientP2PStake,
|
|
5090
|
+
"0x18eda032": contractErrors.P2PTokenNotSet,
|
|
5091
|
+
"0xdab11ea6": contractErrors.P2PUnstakeRequestPending,
|
|
5092
|
+
"0xeb1ce40b": contractErrors.NoP2PUnstakeRequest,
|
|
5093
|
+
"0xbf2d0ba1": contractErrors.P2PUnstakeCooldownNotPassed,
|
|
5094
|
+
"0x06b663af": contractErrors.SlashAmountExceedsStake,
|
|
5095
|
+
"0xff9b022c": contractErrors.CircleNotActive,
|
|
5096
|
+
"0x3d90c0a6": contractErrors.InvalidCircleId,
|
|
5097
|
+
"0xfb42a67d": contractErrors.CurrencyMismatch,
|
|
5098
|
+
"0xf2775265": contractErrors.CircleFull,
|
|
5099
|
+
"0x784b6c3c": contractErrors.CircleIdMismatch,
|
|
5100
|
+
"0xee240e49": contractErrors.DuplicateAccountName,
|
|
5101
|
+
"0x2ef13105": contractErrors.EmptyName,
|
|
5102
|
+
"0x1b5433c8": contractErrors.AccountBoundToAnotherCircle,
|
|
5103
|
+
"0x549e2555": contractErrors.ExitAmountExceededCircleBalance,
|
|
5104
|
+
"0x865b21e1": contractErrors.UndelegationAmountTooHigh,
|
|
5105
|
+
// Exchange / order lifecycle
|
|
5106
|
+
"0x4bbac5de": contractErrors.ExchangeNotOperational,
|
|
5107
|
+
"0x58db8ed6": contractErrors.OrderNotPlaced,
|
|
5108
|
+
"0x1e3b9629": contractErrors.OrderNotPaid,
|
|
5109
|
+
"0x181b1b2e": contractErrors.OrderStatusInvalid,
|
|
5110
|
+
"0xc56873ba": contractErrors.OrderExpired,
|
|
5111
|
+
"0x7f61b868": contractErrors.OrderAlreadyPaid,
|
|
5112
|
+
"0x03683687": contractErrors.OrderAlreadyCompleted,
|
|
5113
|
+
"0x688c176f": contractErrors.InvalidOrderType,
|
|
5114
|
+
"0x2e757a60": contractErrors.OrderTypeIncorrect,
|
|
5115
|
+
"0x6b1b90b4": contractErrors.OrderNotAccepted,
|
|
5116
|
+
"0x1775c43e": contractErrors.OrderNotAssigned,
|
|
5117
|
+
"0xf42e41a1": contractErrors.OrderAmountExceedsLimit,
|
|
5118
|
+
"0x93845d68": contractErrors.InvalidOrderAmount,
|
|
5119
|
+
"0x138b9d5a": contractErrors.InvalidOrderAmountToCoverFee,
|
|
5120
|
+
"0x5d706033": contractErrors.InvalidOrderId,
|
|
5121
|
+
"0xbb776720": contractErrors.OrderTooEarlyForReassignment,
|
|
5122
|
+
"0x20d5910f": contractErrors.OrderTooLateForReassignment,
|
|
5123
|
+
"0xccd87bf0": contractErrors.ReAssignmentNotRequired,
|
|
5124
|
+
"0xb20277f8": contractErrors.TipAlreadyGiven,
|
|
5125
|
+
"0xdf9f707c": contractErrors.CashbackTransferFailed,
|
|
5126
|
+
// Order limits
|
|
5127
|
+
"0xe595a7bf": contractErrors.DailyBuyOrderLimitExceeded,
|
|
5128
|
+
"0x675dbc86": contractErrors.MonthlyBuyOrderLimitExceeded,
|
|
5129
|
+
"0x64301cb8": contractErrors.SellOrderAmountLimitExceeded,
|
|
5130
|
+
"0x91da284f": contractErrors.BuyOrderAmountExceedsLimit,
|
|
5131
|
+
"0xb407b9ec": contractErrors.SellOrderAmountExceedsLimit,
|
|
5132
|
+
"0x4b29cf0a": contractErrors.BuyAmountExceedsUsdcLimit,
|
|
5133
|
+
"0xbba2edf9": contractErrors.SellAmountExceedsFiatLimit,
|
|
5134
|
+
"0x7e2ee654": contractErrors.DailyVolumeLimitExceeded,
|
|
5135
|
+
"0x49de1789": contractErrors.MonthlyVolumeLimitExceeded,
|
|
5136
|
+
"0xb14a1ff3": contractErrors.UserYearlyVolumeLimitExceeded,
|
|
5137
|
+
// Dispute
|
|
5138
|
+
"0x07a2454f": contractErrors.DisputeTimeNotReached,
|
|
5139
|
+
"0xb28c3e29": contractErrors.DisputeTimeExpired,
|
|
5140
|
+
"0x2a829f07": contractErrors.InvalidOrderStatusToRaiseDispute,
|
|
5141
|
+
"0x88d039ce": contractErrors.DisputeNotRaised,
|
|
5142
|
+
"0x3764a75c": contractErrors.CannotRaiseDisputeTwice,
|
|
5143
|
+
"0x866e9f89": contractErrors.DisputeAlreadySettled,
|
|
5144
|
+
"0x6131d13d": contractErrors.TransactionIdMismatch,
|
|
5145
|
+
"0x8ec051b8": contractErrors.AccountNumberMismatch,
|
|
5146
|
+
"0xf8bfad32": contractErrors.NotPaidBuyOrder,
|
|
5147
|
+
// Payment channels
|
|
5148
|
+
"0x552ff5ec": contractErrors.PaymentChannelNotFound,
|
|
5149
|
+
"0xfccd93cf": contractErrors.PaymentChannelNotActive,
|
|
5150
|
+
"0x6764f4d6": contractErrors.PaymentChannelNotApproved,
|
|
5151
|
+
"0xab284291": contractErrors.PaymentChannelNotRejected,
|
|
5152
|
+
"0x99c8ef4d": contractErrors.InvalidPaymentChannelId,
|
|
5153
|
+
"0x0569ab3e": contractErrors.DuplicatePaymentChannel,
|
|
5154
|
+
"0xff4f83ca": contractErrors.OldPaymentChannelNotFound,
|
|
5155
|
+
"0xb1198199": contractErrors.NewPaymentChannelNotFound,
|
|
5156
|
+
"0xc905b99a": contractErrors.SamePaymentChannel,
|
|
5157
|
+
"0xcedb41f1": contractErrors.OldPaymentChannelShouldBeInactive,
|
|
5158
|
+
"0x487add97": contractErrors.NewPaymentChannelShouldBeActive,
|
|
5159
|
+
"0x6d4c3f9e": contractErrors.OngoingOrderOnPaymentChannel,
|
|
5160
|
+
"0xc1654697": contractErrors.UpiAlreadySent,
|
|
5161
|
+
"0xaa60ec26": contractErrors.InvalidOrderUpi,
|
|
5162
|
+
"0x81c2b982": contractErrors.NoFiatLiquidity,
|
|
5163
|
+
// Merchant
|
|
5164
|
+
"0x5d04ff4c": contractErrors.NotEnoughEligibleMerchants,
|
|
5165
|
+
"0xa6af7ebe": contractErrors.MerchantNotRegistered,
|
|
5166
|
+
"0x7290a612": contractErrors.MerchantNotApproved,
|
|
5167
|
+
"0xf4a1e014": contractErrors.MerchantAlreadyRegistered,
|
|
5168
|
+
"0x8713aaba": contractErrors.MerchantAlreadyRejected,
|
|
5169
|
+
"0x9ae55bc7": contractErrors.MerchantBlacklisted,
|
|
5170
|
+
"0x0ee0b659": contractErrors.MerchantNotBlacklisted,
|
|
5171
|
+
"0x5f765689": contractErrors.MerchantAlreadyBlacklisted,
|
|
5172
|
+
"0x9c54e5a8": contractErrors.MerchantHasOngoingOrders,
|
|
5173
|
+
"0x70d753bd": contractErrors.MerchantNotFullfilledEligibilityThreshold,
|
|
5174
|
+
"0xc0b6c919": contractErrors.InvalidMerchant,
|
|
5175
|
+
// Staking / unstaking
|
|
5176
|
+
"0x3fd2347e": contractErrors.StakeAmountTooLow,
|
|
5177
|
+
"0x703cde0a": contractErrors.AdditionalStakeNotAllowed,
|
|
5178
|
+
"0xa9de99ae": contractErrors.UnstakeRequestPending,
|
|
5179
|
+
"0x0b7c70f3": contractErrors.UnstakeRequestNotPending,
|
|
5180
|
+
"0xe665491f": contractErrors.UnstakeAmountExceeded,
|
|
5181
|
+
"0x2d3087f9": contractErrors.ZeroUnstakeAmount,
|
|
5182
|
+
"0x1b1d7861": contractErrors.NoWithdrawableAmount,
|
|
5183
|
+
"0xcacf989a": contractErrors.NoStake,
|
|
5184
|
+
"0x21311aa3": contractErrors.NoStakers,
|
|
5185
|
+
"0xd06ff88e": contractErrors.InsufficientStakedAmount,
|
|
5186
|
+
"0x9ab7872d": contractErrors.CooldownNotPassed,
|
|
5187
|
+
"0x73380d99": contractErrors.ClaimableRewardsNotAvailable,
|
|
5188
|
+
// Delegation
|
|
5189
|
+
"0xec4b3ce6": contractErrors.ExitWouldBreachDelegationInvariant,
|
|
5190
|
+
"0x8f90a426": contractErrors.AggregateDelegationExceedsTotalStaked,
|
|
5191
|
+
"0x2cc11576": contractErrors.InsufficientMerchantRewards,
|
|
5192
|
+
// Migration
|
|
5193
|
+
"0x92aa7d0f": contractErrors.InvalidMigrationStatus,
|
|
5194
|
+
"0x7ff47425": contractErrors.MigrationRequestNotPending,
|
|
5195
|
+
"0x88ddec46": contractErrors.MigrationAlreadyRequested,
|
|
5196
|
+
// Token / currency
|
|
5197
|
+
"0xc991cbb1": contractErrors.TokenAlreadyExists,
|
|
5198
|
+
"0xcbdb7b30": contractErrors.TokenNotFound,
|
|
5199
|
+
"0x9f11a53f": contractErrors.TokenEmpty,
|
|
5200
|
+
"0x02a6fdd2": contractErrors.CurrencyNotSupported,
|
|
5201
|
+
"0xf5993428": contractErrors.InvalidCurrency,
|
|
5202
|
+
// USDC / transfer
|
|
5203
|
+
"0x149f9fca": contractErrors.UsdtTransferFailed,
|
|
5204
|
+
"0x47bfece5": contractErrors.UsdtTransferFailedWithErrorMessage,
|
|
5205
|
+
"0x279bbc0c": contractErrors.UsdtTransferFailedWithPanic,
|
|
5206
|
+
"0xfb8f41b2": contractErrors.InsufficientAllowance,
|
|
5207
|
+
// ZK Passport
|
|
5208
|
+
"0xfd8d4a6d": contractErrors.ZKPassportVerifierNotSet,
|
|
5209
|
+
"0xb87078f9": contractErrors.ZKPassportDomainEmpty,
|
|
5210
|
+
"0x5eadc4c2": contractErrors.ZKPassportScopeEmpty,
|
|
5211
|
+
"0x7642fe15": contractErrors.PassportAlreadyVerified,
|
|
5212
|
+
"0x1fa24b35": contractErrors.ZKPassportProofInvalid,
|
|
5213
|
+
"0x36bdb7b6": contractErrors.ZKPassportIdentifierAlreadyVerified,
|
|
5214
|
+
"0xd13a7934": contractErrors.ZKPassportInvalidScope,
|
|
5215
|
+
"0x69f5bfe7": contractErrors.ZKPassportUnexpectedSender,
|
|
5216
|
+
"0x0464115c": contractErrors.ZKPassportAgeBelowMinimum,
|
|
5217
|
+
"0x48183836": contractErrors.ZKPassportMinAgeTooHigh,
|
|
5218
|
+
// Chainlink / oracle
|
|
5219
|
+
"0x7f73f237": contractErrors.UnexpectedRequestId,
|
|
5220
|
+
"0xab948796": contractErrors.OnlyRouterCanFulfill,
|
|
5221
|
+
"0x61982c98": contractErrors.RequestFailed,
|
|
5222
|
+
"0xab66be18": contractErrors.SourceCodeMismatch,
|
|
5223
|
+
"0xff2826ef": contractErrors.ZeroMarketPrice,
|
|
5224
|
+
"0xbb6c216c": contractErrors.InvalidComputedPrices,
|
|
5225
|
+
"0x3a8fbef4": contractErrors.NotPriceUpdaterForCurrency,
|
|
5226
|
+
"0x3e2c36f2": contractErrors.ThresholdNotConfigured,
|
|
5227
|
+
"0x71c4efed": contractErrors.SlippageExceeded,
|
|
5228
|
+
// Reputation / verification
|
|
5229
|
+
"0x071ea33c": contractErrors.UserHasNoReputation,
|
|
5230
|
+
"0xd2e1e6e0": contractErrors.ZeroReputationPoints,
|
|
5231
|
+
"0x3c0ca622": contractErrors.NoReputation,
|
|
5232
|
+
"0x412dd2b1": contractErrors.InsufficientRP,
|
|
5233
|
+
"0x0f165e7b": contractErrors.NullifierAlreadyVerified,
|
|
5234
|
+
"0x439cc0cd": contractErrors.VerificationFailed,
|
|
5235
|
+
"0x2366073b": contractErrors.InvalidSocialPlatform,
|
|
5236
|
+
"0x2f850b6b": contractErrors.SocialAlreadyVerified,
|
|
5237
|
+
"0x466f52a8": contractErrors.YearFieldNotInProof,
|
|
5238
|
+
"0x4d460588": contractErrors.UserIdFieldNotInProof,
|
|
5239
|
+
"0xa18ea4e8": contractErrors.UserIdAlreadyVerified,
|
|
5240
|
+
"0x69470b13": contractErrors.UsernameAlreadyVerified,
|
|
5241
|
+
"0x8390b2dd": contractErrors.UsernameNotInProof,
|
|
5242
|
+
"0xef053cf4": contractErrors.LinkedInOnlyRpUpdates,
|
|
5243
|
+
"0x355b0709": contractErrors.FacebookOnlyRpUpdates,
|
|
5244
|
+
// Voting / referral
|
|
5245
|
+
"0x7aabdfe3": contractErrors.AlreadyReferred,
|
|
5246
|
+
"0x83463f4a": contractErrors.SelfReferralNotAllowed,
|
|
5247
|
+
"0x69f6994a": contractErrors.NotEligibleToRefer,
|
|
5248
|
+
"0x1b19ad97": contractErrors.MerchantMonthlyReferralLimitReached,
|
|
5249
|
+
"0x944a2241": contractErrors.NoRecommender,
|
|
5250
|
+
"0x0ece93a6": contractErrors.RecommendationAlreadyClaimed,
|
|
5251
|
+
"0x74785d0f": contractErrors.CannotVoteYourself,
|
|
5252
|
+
"0xc26d5f75": contractErrors.VotesPerEpochExceeded,
|
|
5253
|
+
"0x7c9a1cf9": contractErrors.AlreadyVoted,
|
|
5254
|
+
"0x403e7fa6": contractErrors.FunctionNotFound,
|
|
5255
|
+
// Campaign
|
|
5256
|
+
"0x7a551e38": contractErrors.CampaignNotActive,
|
|
5257
|
+
"0x668ca75d": contractErrors.InvalidManagerDetails,
|
|
5258
|
+
"0x2f950361": contractErrors.UnclaimedRewardsExist,
|
|
5259
|
+
"0x626b7c00": contractErrors.RewardAlreadyClaimed,
|
|
5260
|
+
"0x902ade67": contractErrors.OnlyNewUsersAllowed,
|
|
5261
|
+
"0x22a5e34b": contractErrors.ManagerNotFound,
|
|
5262
|
+
"0xa1610e37": contractErrors.ManagerInactive,
|
|
5263
|
+
"0x3fb087f4": contractErrors.NoRewards,
|
|
5264
|
+
"0x3eedee0f": contractErrors.InvalidCampaignId,
|
|
5265
|
+
"0x302c5138": contractErrors.CannotClaimRevenueForCurrentMonth,
|
|
5266
|
+
// Referral reward config
|
|
5267
|
+
"0x074a6991": contractErrors.RewardPercentageTooHigh,
|
|
5268
|
+
// Signature / nonce
|
|
5269
|
+
"0x1fb09b80": contractErrors.NonceAlreadyUsed,
|
|
5270
|
+
"0x2fdec18b": contractErrors.SignatureValidationFailed,
|
|
5271
|
+
// Misc
|
|
5272
|
+
"0xe6c4247b": contractErrors.InvalidAddress,
|
|
5273
|
+
"0x3eb17c88": contractErrors.InvalidBlockAmount,
|
|
5274
|
+
"0x2c5211c6": contractErrors.InvalidAmount,
|
|
5275
|
+
"0xb4fa3fb3": contractErrors.InvalidInput,
|
|
5276
|
+
"0x1117a646": contractErrors.InvalidStatusTransition,
|
|
5277
|
+
"0xa24a13a6": contractErrors.ArrayLengthMismatch,
|
|
5278
|
+
"0xebb6f34b": contractErrors.UserIsBlacklisted,
|
|
5279
|
+
"0xd92e233d": contractErrors.ZeroAddress,
|
|
5280
|
+
"0x8beb9d16": contractErrors.ReentrancyGuard,
|
|
5281
|
+
"0xbb1cb70b": contractErrors.BatchTooLarge,
|
|
5282
|
+
"0xd97cf1ba": contractErrors.UnderflowSubtraction,
|
|
5283
|
+
"0xc9b16952": contractErrors.TargetLongerThanData
|
|
5284
|
+
};
|
|
5285
|
+
|
|
5286
|
+
// src/contracts/order-flow/index.ts
|
|
5287
|
+
import { ResultAsync as ResultAsync7 } from "neverthrow";
|
|
5288
|
+
|
|
5289
|
+
// src/orders/internal/routing/errors.ts
|
|
5290
|
+
var OrderRoutingError = class extends SdkError {
|
|
5291
|
+
constructor(message, options) {
|
|
5292
|
+
super(message, options);
|
|
5293
|
+
this.name = "OrderRoutingError";
|
|
5294
|
+
}
|
|
5295
|
+
};
|
|
5296
|
+
|
|
5297
|
+
// src/orders/internal/routing/validation.ts
|
|
5298
|
+
import { z as z6 } from "zod";
|
|
5299
|
+
var ZodCircleScoreStateSchema = z6.object({
|
|
5300
|
+
activeMerchantsCount: z6.coerce.number()
|
|
5301
|
+
});
|
|
5302
|
+
var ZodCircleMetricsForRoutingSchema = z6.object({
|
|
5303
|
+
circleScore: z6.coerce.number(),
|
|
5304
|
+
circleStatus: z6.string(),
|
|
5305
|
+
scoreState: ZodCircleScoreStateSchema
|
|
5306
|
+
});
|
|
5307
|
+
var ZodCircleForRoutingSchema = z6.object({
|
|
5308
|
+
circleId: z6.string(),
|
|
5309
|
+
currency: z6.string(),
|
|
5310
|
+
metrics: ZodCircleMetricsForRoutingSchema
|
|
5311
|
+
});
|
|
5312
|
+
var ZodCirclesForRoutingResponseSchema = z6.object({
|
|
5313
|
+
circles: z6.array(ZodCircleForRoutingSchema)
|
|
5314
|
+
});
|
|
5315
|
+
var ZodCheckCircleEligibilityParamsSchema = z6.object({
|
|
5316
|
+
circleId: z6.bigint(),
|
|
5317
|
+
currency: z6.string(),
|
|
5318
|
+
user: ZodAddressSchema,
|
|
5319
|
+
usdtAmount: z6.bigint(),
|
|
5320
|
+
fiatAmount: z6.bigint(),
|
|
5321
|
+
orderType: z6.bigint(),
|
|
5322
|
+
preferredPCConfigId: z6.bigint()
|
|
5323
|
+
});
|
|
5324
|
+
var ZodSelectCircleParamsSchema = z6.object({
|
|
5325
|
+
currency: z6.string().min(1),
|
|
5326
|
+
user: ZodAddressSchema,
|
|
5327
|
+
usdtAmount: z6.bigint(),
|
|
5328
|
+
fiatAmount: z6.bigint(),
|
|
5329
|
+
orderType: z6.bigint(),
|
|
5330
|
+
preferredPCConfigId: z6.bigint()
|
|
5331
|
+
});
|
|
5332
|
+
|
|
5333
|
+
// src/contracts/order-flow/index.ts
|
|
5334
|
+
function checkCircleEligibility(publicClient, contractAddress, params, logger = noopLogger) {
|
|
5335
|
+
return validate(
|
|
5336
|
+
ZodCheckCircleEligibilityParamsSchema,
|
|
5337
|
+
params,
|
|
5338
|
+
(message, cause, d) => new OrderRoutingError(message, { code: "VALIDATION_ERROR", cause, context: { data: d } })
|
|
5339
|
+
).asyncAndThen((validated) => {
|
|
5340
|
+
logger.debug("checking on-chain eligibility", {
|
|
5341
|
+
circleId: String(validated.circleId),
|
|
5342
|
+
contractAddress
|
|
5343
|
+
});
|
|
5344
|
+
return ResultAsync7.fromPromise(
|
|
5345
|
+
publicClient.readContract({
|
|
5346
|
+
address: contractAddress,
|
|
5347
|
+
abi: ABIS.FACETS.ORDER_FLOW,
|
|
5348
|
+
functionName: "getAssignableMerchantsFromCircle",
|
|
5349
|
+
args: [
|
|
5350
|
+
validated.circleId,
|
|
5351
|
+
1n,
|
|
5352
|
+
validated.currency,
|
|
5353
|
+
validated.user,
|
|
5354
|
+
validated.usdtAmount,
|
|
5355
|
+
validated.fiatAmount,
|
|
5356
|
+
validated.orderType,
|
|
5357
|
+
validated.preferredPCConfigId
|
|
5358
|
+
]
|
|
5359
|
+
}),
|
|
5360
|
+
(error) => new OrderRoutingError("Eligibility check failed", {
|
|
5361
|
+
code: "CONTRACT_READ_ERROR",
|
|
5362
|
+
cause: error,
|
|
5363
|
+
context: { circleId: String(params.circleId) }
|
|
5364
|
+
})
|
|
5365
|
+
);
|
|
5366
|
+
}).map((merchants) => {
|
|
5367
|
+
const arr = merchants;
|
|
5368
|
+
const eligible = arr.length >= 1;
|
|
5369
|
+
logger.debug("eligibility check result", {
|
|
5370
|
+
circleId: String(params.circleId),
|
|
5371
|
+
assignableMerchants: arr.length,
|
|
5372
|
+
eligible
|
|
5373
|
+
});
|
|
5374
|
+
return eligible;
|
|
5375
|
+
});
|
|
5376
|
+
}
|
|
5377
|
+
|
|
5378
|
+
// src/contracts/p2p-config/index.ts
|
|
5379
|
+
import { ResultAsync as ResultAsync8 } from "neverthrow";
|
|
5380
|
+
import { stringToHex as stringToHex4 } from "viem";
|
|
5381
|
+
|
|
5382
|
+
// src/prices/errors.ts
|
|
5383
|
+
var PricesError = class extends SdkError {
|
|
5384
|
+
constructor(message, options) {
|
|
5385
|
+
super(message, options);
|
|
5386
|
+
this.name = "PricesError";
|
|
5387
|
+
}
|
|
5388
|
+
};
|
|
5389
|
+
|
|
5390
|
+
// src/prices/validation.ts
|
|
5391
|
+
import { z as z7 } from "zod";
|
|
5392
|
+
var ZodCurrencyScopedParamsSchema = z7.object({
|
|
5393
|
+
currency: ZodCurrencySchema
|
|
5394
|
+
});
|
|
5395
|
+
|
|
5396
|
+
// src/contracts/p2p-config/index.ts
|
|
5397
|
+
function getPriceConfig(publicClient, diamondAddress, params) {
|
|
5398
|
+
return validate(
|
|
5399
|
+
ZodCurrencyScopedParamsSchema,
|
|
5400
|
+
params,
|
|
5401
|
+
(message, cause, data) => new PricesError(message, {
|
|
5402
|
+
code: "VALIDATION_ERROR",
|
|
5403
|
+
cause,
|
|
5404
|
+
context: { params: data }
|
|
5405
|
+
})
|
|
5406
|
+
).asyncAndThen(
|
|
5407
|
+
(validated) => ResultAsync8.fromPromise(
|
|
5408
|
+
publicClient.readContract({
|
|
5409
|
+
address: diamondAddress,
|
|
5410
|
+
abi: ABIS.FACETS.CONFIG,
|
|
5411
|
+
functionName: "getPriceConfig",
|
|
5412
|
+
args: [stringToHex4(validated.currency, { size: 32 })]
|
|
5413
|
+
}),
|
|
5414
|
+
(error) => new PricesError("Failed to read price config", {
|
|
5415
|
+
code: "CONTRACT_READ_ERROR",
|
|
5416
|
+
cause: error,
|
|
5417
|
+
context: { currency: validated.currency, diamondAddress }
|
|
5418
|
+
})
|
|
5419
|
+
)
|
|
5420
|
+
);
|
|
5421
|
+
}
|
|
5422
|
+
function getReputationPerUsdcLimit(publicClient, diamondAddress, params) {
|
|
5423
|
+
return validate(
|
|
5424
|
+
ZodCurrencyScopedParamsSchema,
|
|
5425
|
+
params,
|
|
5426
|
+
(message, cause, data) => new PricesError(message, {
|
|
5427
|
+
code: "VALIDATION_ERROR",
|
|
5428
|
+
cause,
|
|
5429
|
+
context: { params: data }
|
|
5430
|
+
})
|
|
5431
|
+
).asyncAndThen(
|
|
5432
|
+
(validated) => ResultAsync8.fromPromise(
|
|
5433
|
+
publicClient.readContract({
|
|
5434
|
+
address: diamondAddress,
|
|
5435
|
+
abi: ABIS.DIAMOND,
|
|
5436
|
+
functionName: "getRpPerUsdtLimitRational",
|
|
5437
|
+
args: [stringToHex4(validated.currency, { size: 32 })]
|
|
5438
|
+
}),
|
|
5439
|
+
(error) => new PricesError("Failed to read reputation-per-USDC limit", {
|
|
5440
|
+
code: "CONTRACT_READ_ERROR",
|
|
5441
|
+
cause: error,
|
|
5442
|
+
context: { currency: validated.currency, diamondAddress }
|
|
5443
|
+
})
|
|
5444
|
+
).map(([numerator, denominator]) => ({
|
|
5445
|
+
numerator,
|
|
5446
|
+
denominator,
|
|
5447
|
+
multiplier: numerator > 0n ? Number(denominator) / Number(numerator) : 0
|
|
5448
|
+
}))
|
|
5449
|
+
);
|
|
5450
|
+
}
|
|
5451
|
+
|
|
5452
|
+
// src/contracts/reputation-manager/writes.ts
|
|
5453
|
+
import { Result as Result2 } from "neverthrow";
|
|
5454
|
+
import { encodeFunctionData as encodeFunctionData7 } from "viem";
|
|
5455
|
+
|
|
5456
|
+
// src/zkkyc/errors.ts
|
|
5457
|
+
var ZkkycError = class extends SdkError {
|
|
5458
|
+
constructor(message, options) {
|
|
5459
|
+
super(message, options);
|
|
5460
|
+
this.name = "ZkkycError";
|
|
5461
|
+
}
|
|
5462
|
+
};
|
|
5463
|
+
|
|
5464
|
+
// src/zkkyc/validation.ts
|
|
5465
|
+
import { z as z8 } from "zod";
|
|
5466
|
+
var ZodAnonAadharProofParamsSchema = z8.object({
|
|
5467
|
+
nullifierSeed: z8.bigint(),
|
|
5468
|
+
nullifier: z8.bigint(),
|
|
5469
|
+
timestamp: z8.bigint(),
|
|
5470
|
+
signal: z8.bigint(),
|
|
5471
|
+
revealArray: z8.tuple([z8.bigint(), z8.bigint(), z8.bigint(), z8.bigint()]),
|
|
5472
|
+
packedGroth16Proof: z8.tuple([
|
|
5473
|
+
z8.bigint(),
|
|
5474
|
+
z8.bigint(),
|
|
5475
|
+
z8.bigint(),
|
|
5476
|
+
z8.bigint(),
|
|
5477
|
+
z8.bigint(),
|
|
5478
|
+
z8.bigint(),
|
|
5479
|
+
z8.bigint(),
|
|
5480
|
+
z8.bigint()
|
|
5481
|
+
])
|
|
5482
|
+
});
|
|
5483
|
+
var ZodSocialVerifyParamsSchema = z8.object({
|
|
5484
|
+
_socialName: z8.string(),
|
|
5485
|
+
proofs: z8.array(
|
|
5486
|
+
z8.object({
|
|
5487
|
+
claimInfo: z8.object({
|
|
5488
|
+
provider: z8.string(),
|
|
5489
|
+
parameters: z8.string(),
|
|
5490
|
+
context: z8.string()
|
|
5491
|
+
}),
|
|
5492
|
+
signedClaim: z8.object({
|
|
5493
|
+
claim: z8.object({
|
|
5494
|
+
identifier: z8.string(),
|
|
5495
|
+
owner: ZodAddressSchema,
|
|
5496
|
+
timestampS: z8.number(),
|
|
5497
|
+
epoch: z8.number()
|
|
5498
|
+
}),
|
|
5499
|
+
signatures: z8.array(z8.string())
|
|
5500
|
+
})
|
|
5501
|
+
})
|
|
5502
|
+
)
|
|
5503
|
+
});
|
|
5504
|
+
var ZodSolidityVerifierParametersSchema = z8.object({
|
|
5505
|
+
version: z8.string().refine((val) => val.startsWith("0x"), {
|
|
5506
|
+
message: "Version must be a hex string"
|
|
5507
|
+
}),
|
|
5508
|
+
proofVerificationData: z8.object({
|
|
5509
|
+
vkeyHash: z8.string().refine((val) => /^0x[a-fA-F0-9]{64}$/.test(val), {
|
|
5510
|
+
message: "Invalid bytes32 hex string"
|
|
5511
|
+
}),
|
|
5512
|
+
proof: z8.string().refine((val) => val.startsWith("0x"), {
|
|
5513
|
+
message: "Proof must be a hex string"
|
|
5514
|
+
}),
|
|
5515
|
+
publicInputs: z8.array(
|
|
5516
|
+
z8.string().refine((val) => /^0x[a-fA-F0-9]{64}$/.test(val), {
|
|
5517
|
+
message: "Each public input must be a valid bytes32 hex string"
|
|
5518
|
+
})
|
|
5519
|
+
)
|
|
5520
|
+
}),
|
|
5521
|
+
committedInputs: z8.string().refine((val) => val.startsWith("0x"), {
|
|
5522
|
+
message: "Committed inputs must be a hex string"
|
|
5523
|
+
}),
|
|
5524
|
+
serviceConfig: z8.object({
|
|
5525
|
+
validityPeriodInSeconds: z8.number().int().nonnegative(),
|
|
5526
|
+
domain: z8.string(),
|
|
5527
|
+
scope: z8.string(),
|
|
5528
|
+
devMode: z8.boolean()
|
|
5529
|
+
})
|
|
5530
|
+
});
|
|
5531
|
+
var ZodZkPassportRegisterParamsSchema = z8.object({
|
|
5532
|
+
params: ZodSolidityVerifierParametersSchema,
|
|
5533
|
+
isIDCard: z8.boolean()
|
|
5534
|
+
});
|
|
5535
|
+
|
|
5536
|
+
// src/contracts/reputation-manager/writes.ts
|
|
5537
|
+
function prepareSocialVerify(reputationManagerAddress, params) {
|
|
5538
|
+
return validate(
|
|
5539
|
+
ZodSocialVerifyParamsSchema,
|
|
5540
|
+
params,
|
|
5541
|
+
(message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
|
|
5542
|
+
).andThen(
|
|
5543
|
+
(validated) => Result2.fromThrowable(
|
|
5544
|
+
() => ({
|
|
5545
|
+
to: reputationManagerAddress,
|
|
5546
|
+
data: encodeFunctionData7({
|
|
5547
|
+
abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
|
|
5548
|
+
functionName: "socialVerify",
|
|
5549
|
+
args: [
|
|
5550
|
+
validated._socialName,
|
|
5551
|
+
validated.proofs.map((proof) => ({
|
|
5552
|
+
...proof,
|
|
5553
|
+
signedClaim: {
|
|
5554
|
+
...proof.signedClaim,
|
|
5555
|
+
claim: {
|
|
5556
|
+
...proof.signedClaim.claim,
|
|
5557
|
+
identifier: proof.signedClaim.claim.identifier
|
|
5558
|
+
},
|
|
5559
|
+
signatures: proof.signedClaim.signatures
|
|
5560
|
+
}
|
|
5561
|
+
}))
|
|
5562
|
+
]
|
|
5563
|
+
})
|
|
5564
|
+
}),
|
|
5565
|
+
(error) => new ZkkycError("Failed to encode socialVerify", {
|
|
5566
|
+
code: "ENCODE_ERROR",
|
|
5567
|
+
cause: error
|
|
5568
|
+
})
|
|
5569
|
+
)()
|
|
5570
|
+
);
|
|
5571
|
+
}
|
|
5572
|
+
function prepareSubmitAnonAadharProof(reputationManagerAddress, params) {
|
|
5573
|
+
return validate(
|
|
5574
|
+
ZodAnonAadharProofParamsSchema,
|
|
5575
|
+
params,
|
|
5576
|
+
(message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
|
|
5577
|
+
).andThen(
|
|
5578
|
+
(validated) => Result2.fromThrowable(
|
|
5579
|
+
() => ({
|
|
5580
|
+
to: reputationManagerAddress,
|
|
5581
|
+
data: encodeFunctionData7({
|
|
5582
|
+
abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
|
|
5583
|
+
functionName: "submitAnonAadharProof",
|
|
5584
|
+
args: [
|
|
5585
|
+
validated.nullifierSeed,
|
|
5586
|
+
validated.nullifier,
|
|
5587
|
+
validated.timestamp,
|
|
5588
|
+
validated.signal,
|
|
5589
|
+
validated.revealArray,
|
|
5590
|
+
validated.packedGroth16Proof
|
|
5591
|
+
]
|
|
5592
|
+
})
|
|
5593
|
+
}),
|
|
5594
|
+
(error) => new ZkkycError("Failed to encode submitAnonAadharProof", {
|
|
5595
|
+
code: "ENCODE_ERROR",
|
|
5596
|
+
cause: error
|
|
5597
|
+
})
|
|
5598
|
+
)()
|
|
5599
|
+
);
|
|
5600
|
+
}
|
|
5601
|
+
function prepareZkPassportRegister(reputationManagerAddress, params) {
|
|
5602
|
+
return validate(
|
|
5603
|
+
ZodZkPassportRegisterParamsSchema,
|
|
5604
|
+
params,
|
|
5605
|
+
(message, cause, data) => new ZkkycError(message, { code: "VALIDATION_ERROR", cause, context: { params: data } })
|
|
5606
|
+
).andThen(
|
|
5607
|
+
(validated) => Result2.fromThrowable(
|
|
5608
|
+
() => {
|
|
5609
|
+
const { proofVerificationData, serviceConfig, committedInputs, version } = validated.params;
|
|
5610
|
+
const proofVerificationParams = {
|
|
5611
|
+
version,
|
|
5612
|
+
proofVerificationData: {
|
|
5613
|
+
vkeyHash: proofVerificationData.vkeyHash,
|
|
5614
|
+
proof: proofVerificationData.proof,
|
|
5615
|
+
publicInputs: proofVerificationData.publicInputs
|
|
5616
|
+
},
|
|
5617
|
+
committedInputs,
|
|
5618
|
+
serviceConfig: {
|
|
5619
|
+
validityPeriodInSeconds: BigInt(serviceConfig.validityPeriodInSeconds),
|
|
5620
|
+
domain: serviceConfig.domain,
|
|
5621
|
+
scope: serviceConfig.scope,
|
|
5622
|
+
devMode: serviceConfig.devMode
|
|
5623
|
+
}
|
|
5624
|
+
};
|
|
5625
|
+
return {
|
|
5626
|
+
to: reputationManagerAddress,
|
|
5627
|
+
data: encodeFunctionData7({
|
|
5628
|
+
abi: ABIS.EXTERNAL.REPUTATION_MANAGER,
|
|
5629
|
+
functionName: "zkPassportRegister",
|
|
5630
|
+
args: [proofVerificationParams, validated.isIDCard]
|
|
5631
|
+
})
|
|
5632
|
+
};
|
|
5633
|
+
},
|
|
5634
|
+
(error) => new ZkkycError("Failed to encode zkPassportRegister", {
|
|
5635
|
+
code: "ENCODE_ERROR",
|
|
5636
|
+
cause: error
|
|
5637
|
+
})
|
|
5638
|
+
)()
|
|
5639
|
+
);
|
|
5640
|
+
}
|
|
5641
|
+
|
|
5642
|
+
// src/contracts/tx-limits/index.ts
|
|
5643
|
+
import { ResultAsync as ResultAsync9 } from "neverthrow";
|
|
5644
|
+
import { formatUnits, stringToHex as stringToHex5 } from "viem";
|
|
5645
|
+
|
|
5646
|
+
// src/profile/errors.ts
|
|
5647
|
+
var ProfileError = class extends SdkError {
|
|
5648
|
+
constructor(message, options) {
|
|
5649
|
+
super(message, options);
|
|
5650
|
+
this.name = "ProfileError";
|
|
5651
|
+
}
|
|
5652
|
+
};
|
|
5653
|
+
|
|
5654
|
+
// src/profile/validation.ts
|
|
5655
|
+
import { z as z9 } from "zod";
|
|
5656
|
+
var ZodUsdcBalanceParamsSchema = z9.object({
|
|
5657
|
+
address: ZodAddressSchema
|
|
5658
|
+
});
|
|
5659
|
+
var ZodUsdcAllowanceParamsSchema = z9.object({
|
|
5660
|
+
owner: ZodAddressSchema
|
|
5661
|
+
});
|
|
5662
|
+
var ZodGetBalancesParamsSchema = z9.object({
|
|
5663
|
+
address: ZodAddressSchema,
|
|
5664
|
+
currency: ZodCurrencySchema
|
|
5665
|
+
});
|
|
5666
|
+
var ZodTxLimitsParamsSchema = z9.object({
|
|
5667
|
+
address: ZodAddressSchema,
|
|
5668
|
+
currency: ZodCurrencySchema
|
|
5669
|
+
});
|
|
5670
|
+
|
|
5671
|
+
// src/contracts/tx-limits/index.ts
|
|
5672
|
+
function getTxLimits(publicClient, diamondAddress, params) {
|
|
5673
|
+
return validate(
|
|
5674
|
+
ZodTxLimitsParamsSchema,
|
|
5675
|
+
params,
|
|
5676
|
+
(message, cause, data) => new ProfileError(message, {
|
|
5677
|
+
code: "VALIDATION_ERROR",
|
|
5678
|
+
cause,
|
|
5679
|
+
context: { params: data }
|
|
5680
|
+
})
|
|
5681
|
+
).asyncAndThen(
|
|
5682
|
+
(validated) => ResultAsync9.fromPromise(
|
|
5683
|
+
publicClient.readContract({
|
|
5684
|
+
address: diamondAddress,
|
|
5685
|
+
abi: ABIS.FACETS.ORDER_FLOW,
|
|
5686
|
+
functionName: "userTxLimit",
|
|
5687
|
+
args: [validated.address, stringToHex5(validated.currency, { size: 32 })]
|
|
5688
|
+
}),
|
|
5689
|
+
(error) => new ProfileError("Failed to read tx limits", {
|
|
5690
|
+
code: "CONTRACT_READ_ERROR",
|
|
5691
|
+
cause: error,
|
|
5692
|
+
context: { address: validated.address, currency: validated.currency, diamondAddress }
|
|
5693
|
+
})
|
|
5694
|
+
).map(([buyLimit, sellLimit]) => ({
|
|
5695
|
+
buyLimit: Number(formatUnits(buyLimit, 6)),
|
|
5696
|
+
sellLimit: Number(formatUnits(sellLimit, 6))
|
|
5697
|
+
}))
|
|
5698
|
+
);
|
|
5699
|
+
}
|
|
5700
|
+
|
|
5701
|
+
// src/contracts/usdc/index.ts
|
|
5702
|
+
import { ResultAsync as ResultAsync10 } from "neverthrow";
|
|
5703
|
+
import { erc20Abi as erc20Abi3 } from "viem";
|
|
5704
|
+
function getUsdcBalance(publicClient, usdcAddress, params) {
|
|
5705
|
+
return validate(
|
|
5706
|
+
ZodUsdcBalanceParamsSchema,
|
|
5707
|
+
params,
|
|
5708
|
+
(message, cause, data) => new ProfileError(message, {
|
|
5709
|
+
code: "VALIDATION_ERROR",
|
|
5710
|
+
cause,
|
|
5711
|
+
context: { params: data }
|
|
5712
|
+
})
|
|
5713
|
+
).asyncAndThen(
|
|
5714
|
+
(validated) => ResultAsync10.fromPromise(
|
|
5715
|
+
publicClient.readContract({
|
|
5716
|
+
address: usdcAddress,
|
|
5717
|
+
abi: ABIS.EXTERNAL.USDC,
|
|
5718
|
+
functionName: "balanceOf",
|
|
5719
|
+
args: [validated.address]
|
|
5720
|
+
}),
|
|
5721
|
+
(error) => new ProfileError("Failed to read USDC balance", {
|
|
5722
|
+
code: "CONTRACT_READ_ERROR",
|
|
5723
|
+
cause: error,
|
|
5724
|
+
context: { address: validated.address, usdcAddress }
|
|
5725
|
+
})
|
|
5726
|
+
)
|
|
5727
|
+
);
|
|
5728
|
+
}
|
|
5729
|
+
function getUsdcAllowance(publicClient, usdcAddress, diamondAddress, params) {
|
|
5730
|
+
return validate(
|
|
5731
|
+
ZodUsdcAllowanceParamsSchema,
|
|
5732
|
+
params,
|
|
5733
|
+
(message, cause, data) => new ProfileError(message, {
|
|
5734
|
+
code: "VALIDATION_ERROR",
|
|
5735
|
+
cause,
|
|
5736
|
+
context: { params: data }
|
|
5737
|
+
})
|
|
5738
|
+
).asyncAndThen(
|
|
5739
|
+
(validated) => ResultAsync10.fromPromise(
|
|
5740
|
+
publicClient.readContract({
|
|
5741
|
+
address: usdcAddress,
|
|
5742
|
+
abi: erc20Abi3,
|
|
5743
|
+
functionName: "allowance",
|
|
5744
|
+
args: [validated.owner, diamondAddress]
|
|
5745
|
+
}),
|
|
5746
|
+
(error) => new ProfileError("Failed to read USDC allowance", {
|
|
5747
|
+
code: "CONTRACT_READ_ERROR",
|
|
5748
|
+
cause: error,
|
|
5749
|
+
context: { owner: validated.owner, usdcAddress, diamondAddress }
|
|
5750
|
+
})
|
|
5751
|
+
)
|
|
5752
|
+
);
|
|
5753
|
+
}
|
|
5754
|
+
|
|
5755
|
+
// src/orders/internal/routing/routing.ts
|
|
5756
|
+
import { errAsync as errAsync3, okAsync as okAsync3 } from "neverthrow";
|
|
5757
|
+
var EPSILON = 0.25;
|
|
5758
|
+
var RECOVERY_SCALE = 0.3;
|
|
5759
|
+
var BOOTSTRAP_MAX_WEIGHT = 25;
|
|
5760
|
+
var MAX_VALIDATION_ATTEMPTS = 3;
|
|
5761
|
+
function circleWeight(c) {
|
|
5762
|
+
const score = c.metrics.circleScore;
|
|
5763
|
+
if (c.metrics.circleStatus === "paused") {
|
|
5764
|
+
return score * RECOVERY_SCALE;
|
|
5765
|
+
}
|
|
5766
|
+
if (c.metrics.circleStatus === "bootstrap") {
|
|
5767
|
+
return Math.min(score, BOOTSTRAP_MAX_WEIGHT);
|
|
5768
|
+
}
|
|
5769
|
+
return score;
|
|
5770
|
+
}
|
|
5771
|
+
function filterEligibleCircles(circles, orderCurrency) {
|
|
5772
|
+
return circles.filter((c) => c.currency.toLowerCase() === orderCurrency.toLowerCase());
|
|
5773
|
+
}
|
|
5774
|
+
function weightedRandomChoice(arr, weights) {
|
|
5775
|
+
const totalWeight = weights.reduce((sum, w) => sum + w, 0);
|
|
5776
|
+
if (totalWeight === 0) {
|
|
5777
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
5778
|
+
}
|
|
5779
|
+
let rand = Math.random() * totalWeight;
|
|
5780
|
+
for (let i = 0; i < arr.length; i++) {
|
|
5781
|
+
rand -= weights[i];
|
|
5782
|
+
if (rand <= 0) {
|
|
5783
|
+
return arr[i];
|
|
5784
|
+
}
|
|
5785
|
+
}
|
|
5786
|
+
return arr[arr.length - 1];
|
|
5787
|
+
}
|
|
5788
|
+
function selectCircle(eligible) {
|
|
5789
|
+
if (eligible.length === 0) {
|
|
5790
|
+
return null;
|
|
5791
|
+
}
|
|
5792
|
+
const activeCircles = eligible.filter((c) => c.metrics.circleStatus === "active");
|
|
5793
|
+
const isExplore = Math.random() < EPSILON;
|
|
5794
|
+
if (isExplore) {
|
|
5795
|
+
const weights2 = eligible.map(circleWeight);
|
|
5796
|
+
return weightedRandomChoice(eligible, weights2);
|
|
5797
|
+
}
|
|
5798
|
+
if (activeCircles.length === 0) {
|
|
5799
|
+
const weights2 = eligible.map(circleWeight);
|
|
5800
|
+
return weightedRandomChoice(eligible, weights2);
|
|
5801
|
+
}
|
|
5802
|
+
const weights = activeCircles.map((c) => c.metrics.circleScore);
|
|
5803
|
+
return weightedRandomChoice(activeCircles, weights);
|
|
5804
|
+
}
|
|
5805
|
+
function selectCircleForOrderAsync(circles, orderCurrency, validateCircle, logger = noopLogger) {
|
|
5806
|
+
const eligible = filterEligibleCircles(circles, orderCurrency);
|
|
5807
|
+
let remaining = [...eligible];
|
|
5808
|
+
logger.debug("filtering eligible circles", {
|
|
5809
|
+
total: circles.length,
|
|
5810
|
+
eligible: eligible.length,
|
|
5811
|
+
currency: orderCurrency,
|
|
5812
|
+
circles: eligible
|
|
5813
|
+
});
|
|
5814
|
+
if (eligible.length === 0) {
|
|
5815
|
+
logger.warn("no eligible circles found for currency", { currency: orderCurrency });
|
|
5816
|
+
}
|
|
5817
|
+
function attempt(attemptsLeft) {
|
|
5818
|
+
if (attemptsLeft <= 0 || remaining.length === 0) {
|
|
5819
|
+
logger.warn("exhausted all attempts or circles", {
|
|
5820
|
+
attemptsLeft,
|
|
5821
|
+
remainingCircles: remaining.length
|
|
5822
|
+
});
|
|
5823
|
+
return errAsync3(
|
|
5824
|
+
new OrderRoutingError("No eligible circles found", {
|
|
5825
|
+
code: "NO_ELIGIBLE_CIRCLES"
|
|
5826
|
+
})
|
|
5827
|
+
);
|
|
5828
|
+
}
|
|
5829
|
+
const selected = selectCircle(remaining);
|
|
5830
|
+
if (!selected) {
|
|
5831
|
+
return errAsync3(
|
|
5832
|
+
new OrderRoutingError("No eligible circles found", {
|
|
5833
|
+
code: "NO_ELIGIBLE_CIRCLES"
|
|
5834
|
+
})
|
|
5835
|
+
);
|
|
5836
|
+
}
|
|
5837
|
+
const circleId = BigInt(selected.circleId);
|
|
5838
|
+
logger.debug("selected circle, validating on-chain", {
|
|
5839
|
+
circleId: String(circleId),
|
|
5840
|
+
status: selected.metrics.circleStatus,
|
|
5841
|
+
score: selected.metrics.circleScore,
|
|
5842
|
+
attemptsLeft
|
|
5843
|
+
});
|
|
5844
|
+
return validateCircle(circleId).orElse((error) => {
|
|
5845
|
+
logger.warn("validation errored, treating as ineligible", {
|
|
5846
|
+
circleId: String(circleId),
|
|
5847
|
+
error: String(error)
|
|
5848
|
+
});
|
|
5849
|
+
return okAsync3(false);
|
|
5850
|
+
}).andThen((isValid) => {
|
|
5851
|
+
if (isValid) {
|
|
5852
|
+
logger.info("circle validated successfully", { circleId: String(circleId) });
|
|
5853
|
+
return okAsync3(circleId);
|
|
5854
|
+
}
|
|
5855
|
+
logger.debug("circle failed validation, retrying", {
|
|
5856
|
+
circleId: String(circleId),
|
|
5857
|
+
remainingCircles: remaining.length - 1
|
|
5858
|
+
});
|
|
5859
|
+
remaining = remaining.filter((c) => c.circleId !== selected.circleId);
|
|
5860
|
+
return attempt(attemptsLeft - 1);
|
|
5861
|
+
});
|
|
5862
|
+
}
|
|
5863
|
+
return attempt(MAX_VALIDATION_ATTEMPTS);
|
|
5864
|
+
}
|
|
5865
|
+
|
|
5866
|
+
// src/orders/internal/routing/subgraph/queries.ts
|
|
5867
|
+
var CIRCLES_FOR_ROUTING_QUERY = (
|
|
5868
|
+
/* GraphQL */
|
|
5869
|
+
`
|
|
5870
|
+
query CirclesForRouting($currency: Bytes!) {
|
|
5871
|
+
circles(
|
|
5872
|
+
first: 1000
|
|
5873
|
+
where: {
|
|
5874
|
+
currency: $currency
|
|
5875
|
+
metrics_: {
|
|
5876
|
+
circleStatus_in: ["active", "bootstrap", "paused"]
|
|
5877
|
+
}
|
|
5878
|
+
}
|
|
5879
|
+
) {
|
|
5880
|
+
circleId
|
|
5881
|
+
currency
|
|
5882
|
+
metrics {
|
|
5883
|
+
circleScore
|
|
5884
|
+
circleStatus
|
|
5885
|
+
scoreState {
|
|
5886
|
+
activeMerchantsCount
|
|
5887
|
+
}
|
|
5888
|
+
}
|
|
5889
|
+
}
|
|
5890
|
+
}
|
|
5891
|
+
`
|
|
5892
|
+
);
|
|
5893
|
+
|
|
5894
|
+
// src/orders/internal/routing/subgraph/index.ts
|
|
5895
|
+
function getCirclesForRouting(subgraphUrl, currency, logger = noopLogger) {
|
|
5896
|
+
logger.debug("fetching circles from subgraph", { subgraphUrl, currency });
|
|
5897
|
+
return querySubgraph(subgraphUrl, {
|
|
5898
|
+
query: CIRCLES_FOR_ROUTING_QUERY,
|
|
5899
|
+
variables: { currency }
|
|
5900
|
+
}).mapErr(
|
|
5901
|
+
(e) => new OrderRoutingError(e.message, {
|
|
5902
|
+
code: "SUBGRAPH_ERROR",
|
|
5903
|
+
cause: e.cause ?? e,
|
|
5904
|
+
context: e.context
|
|
5905
|
+
})
|
|
5906
|
+
).andThen(
|
|
5907
|
+
(data) => validate(
|
|
5908
|
+
ZodCirclesForRoutingResponseSchema,
|
|
5909
|
+
data,
|
|
5910
|
+
(message, cause, d) => new OrderRoutingError(message, { code: "VALIDATION_ERROR", cause, context: { data: d } })
|
|
5911
|
+
).map((validated) => {
|
|
5912
|
+
const circles = validated.circles.filter(
|
|
5913
|
+
(item) => Number(item.metrics.scoreState.activeMerchantsCount) > 0
|
|
5914
|
+
);
|
|
5915
|
+
logger.info("fetched circles from subgraph", {
|
|
5916
|
+
total: validated.circles.length,
|
|
5917
|
+
withActiveMerchants: circles.length,
|
|
5918
|
+
circles
|
|
5919
|
+
});
|
|
5920
|
+
return circles;
|
|
5921
|
+
})
|
|
5922
|
+
);
|
|
4337
5923
|
}
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
const
|
|
4342
|
-
const
|
|
4343
|
-
const sharedSecret = sharedPoint.slice(1);
|
|
4344
|
-
const { encKey, macKey } = deriveKeys(sharedSecret);
|
|
4345
|
-
const iv = randomBytes(16);
|
|
4346
|
-
const plaintext = new TextEncoder().encode(message);
|
|
4347
|
-
const cipher = cbc(encKey, iv);
|
|
4348
|
-
const ciphertext = cipher.encrypt(plaintext);
|
|
4349
|
-
const macData = concatBytes2(iv, ephemPubKey, ciphertext);
|
|
4350
|
-
const mac = hmac(sha2562, macKey, macData);
|
|
5924
|
+
|
|
5925
|
+
// src/orders/internal/routing/client.ts
|
|
5926
|
+
function createOrderRouter(config) {
|
|
5927
|
+
const { subgraphUrl, publicClient, contractAddress } = config;
|
|
5928
|
+
const logger = config.logger ?? noopLogger;
|
|
4351
5929
|
return {
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
5930
|
+
selectCircle(params) {
|
|
5931
|
+
const currencyHex = stringToHex6(params.currency, { size: 32 });
|
|
5932
|
+
logger.info("selectCircle started", {
|
|
5933
|
+
currency: params.currency,
|
|
5934
|
+
user: params.user,
|
|
5935
|
+
orderType: String(params.orderType)
|
|
5936
|
+
});
|
|
5937
|
+
return getCirclesForRouting(subgraphUrl, currencyHex, logger).andThen(
|
|
5938
|
+
(circles) => selectCircleForOrderAsync(
|
|
5939
|
+
circles,
|
|
5940
|
+
currencyHex,
|
|
5941
|
+
(circleId) => checkCircleEligibility(
|
|
5942
|
+
publicClient,
|
|
5943
|
+
contractAddress,
|
|
5944
|
+
{
|
|
5945
|
+
circleId,
|
|
5946
|
+
currency: currencyHex,
|
|
5947
|
+
user: params.user,
|
|
5948
|
+
usdtAmount: params.usdtAmount,
|
|
5949
|
+
fiatAmount: params.fiatAmount,
|
|
5950
|
+
orderType: params.orderType,
|
|
5951
|
+
preferredPCConfigId: params.preferredPCConfigId
|
|
5952
|
+
},
|
|
5953
|
+
logger
|
|
5954
|
+
),
|
|
5955
|
+
logger
|
|
5956
|
+
)
|
|
5957
|
+
);
|
|
5958
|
+
}
|
|
4356
5959
|
};
|
|
4357
5960
|
}
|
|
4358
|
-
function cipherStringify(encrypted) {
|
|
4359
|
-
const ephemPubKeyBytes = hexToBytes3(encrypted.ephemPublicKey);
|
|
4360
|
-
const compressed = secp256k1.ProjectivePoint.fromHex(ephemPubKeyBytes).toRawBytes(true);
|
|
4361
|
-
const iv = hexToBytes3(encrypted.iv);
|
|
4362
|
-
const mac = hexToBytes3(encrypted.mac);
|
|
4363
|
-
const ciphertext = hexToBytes3(encrypted.ciphertext);
|
|
4364
|
-
return bytesToHex2(concatBytes2(iv, compressed, mac, ciphertext));
|
|
4365
|
-
}
|
|
4366
5961
|
|
|
4367
|
-
// src/
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
5962
|
+
// src/orders/normalize.ts
|
|
5963
|
+
import { err as err4, ok as ok5, Result as Result3 } from "neverthrow";
|
|
5964
|
+
import { hexToString, isAddressEqual, zeroAddress } from "viem";
|
|
5965
|
+
var ORDER_TYPE_MAP = {
|
|
5966
|
+
[ORDER_TYPE.BUY]: "buy",
|
|
5967
|
+
[ORDER_TYPE.SELL]: "sell",
|
|
5968
|
+
[ORDER_TYPE.PAY]: "pay"
|
|
4373
5969
|
};
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
const rawPubKey = account.publicKey;
|
|
4392
|
-
const publicKey = rawPubKey.slice(4);
|
|
4393
|
-
const identity = {
|
|
4394
|
-
address: account.address,
|
|
4395
|
-
publicKey,
|
|
4396
|
-
privateKey
|
|
4397
|
-
};
|
|
4398
|
-
localStorage.setItem(STORAGE_KEY, JSON.stringify(identity));
|
|
4399
|
-
return identity;
|
|
5970
|
+
var ORDER_STATUS_MAP = {
|
|
5971
|
+
[ORDER_STATUS.PLACED]: "placed",
|
|
5972
|
+
[ORDER_STATUS.ACCEPTED]: "accepted",
|
|
5973
|
+
[ORDER_STATUS.PAID]: "paid",
|
|
5974
|
+
[ORDER_STATUS.COMPLETED]: "completed",
|
|
5975
|
+
[ORDER_STATUS.CANCELLED]: "cancelled"
|
|
5976
|
+
};
|
|
5977
|
+
var DISPUTE_STATUS_MAP = {
|
|
5978
|
+
[DISPUTE_STATUS.NONE]: "none",
|
|
5979
|
+
[DISPUTE_STATUS.OPEN]: "open",
|
|
5980
|
+
[DISPUTE_STATUS.RESOLVED]: "resolved"
|
|
5981
|
+
};
|
|
5982
|
+
function malformed(field, value, context) {
|
|
5983
|
+
return new OrdersError(`Unknown ${field}: ${String(value)}`, {
|
|
5984
|
+
code: "MALFORMED_ORDER",
|
|
5985
|
+
context: { field, value, ...context }
|
|
5986
|
+
});
|
|
4400
5987
|
}
|
|
4401
|
-
function
|
|
4402
|
-
const
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
if (
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
5988
|
+
function mapOrderType(v, ctx) {
|
|
5989
|
+
const t = ORDER_TYPE_MAP[v];
|
|
5990
|
+
return t ? ok5(t) : err4(malformed("orderType", v, ctx));
|
|
5991
|
+
}
|
|
5992
|
+
function mapOrderStatus(v, ctx) {
|
|
5993
|
+
const s = ORDER_STATUS_MAP[v];
|
|
5994
|
+
return s ? ok5(s) : err4(malformed("status", v, ctx));
|
|
5995
|
+
}
|
|
5996
|
+
function mapDisputeStatus(v, ctx) {
|
|
5997
|
+
const s = DISPUTE_STATUS_MAP[v];
|
|
5998
|
+
return s ? ok5(s) : err4(malformed("disputeStatus", v, ctx));
|
|
5999
|
+
}
|
|
6000
|
+
function decodeCurrency(hex) {
|
|
6001
|
+
return hexToString(hex, { size: 32 }).replaceAll("\0", "");
|
|
6002
|
+
}
|
|
6003
|
+
function normalizeContractOrder(raw, details) {
|
|
6004
|
+
if (raw.id === 0n && isAddressEqual(raw.user, zeroAddress)) return ok5(null);
|
|
6005
|
+
const ctx = { orderId: raw.id.toString() };
|
|
6006
|
+
return Result3.combine([
|
|
6007
|
+
mapOrderType(raw.orderType, ctx),
|
|
6008
|
+
mapOrderStatus(raw.status, ctx),
|
|
6009
|
+
mapDisputeStatus(raw.disputeInfo.status, ctx)
|
|
6010
|
+
]).map(([type, status, disputeStatus]) => ({
|
|
6011
|
+
orderId: raw.id,
|
|
6012
|
+
type,
|
|
6013
|
+
status,
|
|
6014
|
+
usdcAmount: raw.amount,
|
|
6015
|
+
fiatAmount: raw.fiatAmount,
|
|
6016
|
+
actualUsdcAmount: details.actualUsdtAmount,
|
|
6017
|
+
actualFiatAmount: details.actualFiatAmount,
|
|
6018
|
+
currency: decodeCurrency(raw.currency),
|
|
6019
|
+
user: raw.user,
|
|
6020
|
+
recipient: raw.recipientAddr,
|
|
6021
|
+
acceptedMerchant: raw.acceptedMerchant,
|
|
6022
|
+
placedAt: raw.placedTimestamp,
|
|
6023
|
+
acceptedAt: details.acceptedTimestamp,
|
|
6024
|
+
paidAt: details.paidTimestamp,
|
|
6025
|
+
completedAt: raw.completedTimestamp,
|
|
6026
|
+
circleId: raw.circleId,
|
|
6027
|
+
fixedFeePaid: details.fixedFeePaid,
|
|
6028
|
+
tipsPaid: details.tipsPaid,
|
|
6029
|
+
disputeStatus,
|
|
6030
|
+
encUpi: raw.encUpi,
|
|
6031
|
+
encMerchantUpi: raw.encMerchantUpi,
|
|
6032
|
+
pubkey: raw.pubkey
|
|
6033
|
+
}));
|
|
4421
6034
|
}
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
)
|
|
4455
|
-
);
|
|
4456
|
-
const stringified = yield* safeCipherStringify(encrypted);
|
|
4457
|
-
return ok4(stringified);
|
|
4458
|
-
});
|
|
6035
|
+
function normalizeSubgraphOrder(raw) {
|
|
6036
|
+
const ctx = { orderId: raw.orderId };
|
|
6037
|
+
return Result3.combine([
|
|
6038
|
+
mapOrderType(raw.type, ctx),
|
|
6039
|
+
mapOrderStatus(raw.status, ctx),
|
|
6040
|
+
mapDisputeStatus(raw.disputeStatus, ctx)
|
|
6041
|
+
]).map(([type, status, disputeStatus]) => ({
|
|
6042
|
+
orderId: BigInt(raw.orderId),
|
|
6043
|
+
type,
|
|
6044
|
+
status,
|
|
6045
|
+
usdcAmount: BigInt(raw.usdcAmount),
|
|
6046
|
+
fiatAmount: BigInt(raw.fiatAmount),
|
|
6047
|
+
actualUsdcAmount: BigInt(raw.actualUsdcAmount),
|
|
6048
|
+
actualFiatAmount: BigInt(raw.actualFiatAmount),
|
|
6049
|
+
currency: decodeCurrency(raw.currency),
|
|
6050
|
+
user: raw.userAddress,
|
|
6051
|
+
recipient: raw.usdcRecipientAddress,
|
|
6052
|
+
acceptedMerchant: raw.acceptedMerchantAddress,
|
|
6053
|
+
placedAt: BigInt(raw.placedAt),
|
|
6054
|
+
acceptedAt: BigInt(raw.acceptedAt),
|
|
6055
|
+
paidAt: BigInt(raw.paidAt),
|
|
6056
|
+
completedAt: BigInt(raw.completedAt),
|
|
6057
|
+
circleId: BigInt(raw.circleId),
|
|
6058
|
+
fixedFeePaid: BigInt(raw.fixedFeePaid),
|
|
6059
|
+
tipsPaid: BigInt(raw.tipsPaid),
|
|
6060
|
+
disputeStatus,
|
|
6061
|
+
// Subgraph entity does not currently expose these encryption fields;
|
|
6062
|
+
// consumers needing them should fall back to the contract via getOrder.
|
|
6063
|
+
encUpi: "",
|
|
6064
|
+
encMerchantUpi: "",
|
|
6065
|
+
pubkey: ""
|
|
6066
|
+
}));
|
|
4459
6067
|
}
|
|
4460
|
-
var ZodEncryptedDataSchema = z7.object({
|
|
4461
|
-
ciphertext: z7.string(),
|
|
4462
|
-
iv: z7.string(),
|
|
4463
|
-
mac: z7.string(),
|
|
4464
|
-
ephemPublicKey: z7.string()
|
|
4465
|
-
});
|
|
4466
6068
|
|
|
4467
|
-
// src/
|
|
4468
|
-
import {
|
|
4469
|
-
var ZodPlaceOrderParamsSchema = z8.object({
|
|
4470
|
-
amount: z8.bigint(),
|
|
4471
|
-
recipientAddr: ZodAddressSchema,
|
|
4472
|
-
orderType: z8.number().int().min(0).max(2),
|
|
4473
|
-
currency: ZodCurrencySchema,
|
|
4474
|
-
fiatAmount: z8.bigint(),
|
|
4475
|
-
user: ZodAddressSchema,
|
|
4476
|
-
pubKey: z8.string().optional(),
|
|
4477
|
-
preferredPaymentChannelConfigId: z8.bigint().optional(),
|
|
4478
|
-
fiatAmountLimit: z8.bigint().optional().default(0n)
|
|
4479
|
-
});
|
|
4480
|
-
var ZodSetSellOrderUpiParamsSchema = z8.object({
|
|
4481
|
-
orderId: z8.number().int().nonnegative(),
|
|
4482
|
-
paymentAddress: z8.string().min(1),
|
|
4483
|
-
merchantPublicKey: z8.string().min(1),
|
|
4484
|
-
updatedAmount: z8.bigint()
|
|
4485
|
-
});
|
|
6069
|
+
// src/orders/subgraph/index.ts
|
|
6070
|
+
import { Result as Result4 } from "neverthrow";
|
|
4486
6071
|
|
|
4487
|
-
// src/
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
(
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
6072
|
+
// src/orders/subgraph/queries.ts
|
|
6073
|
+
var ORDERS_BY_USER_QUERY = (
|
|
6074
|
+
/* GraphQL */
|
|
6075
|
+
`
|
|
6076
|
+
query OrdersByUser($user: Bytes!, $skip: Int!, $first: Int!) {
|
|
6077
|
+
orders_collection(
|
|
6078
|
+
where: { userAddress: $user }
|
|
6079
|
+
orderBy: placedAt
|
|
6080
|
+
orderDirection: desc
|
|
6081
|
+
skip: $skip
|
|
6082
|
+
first: $first
|
|
6083
|
+
) {
|
|
6084
|
+
orderId
|
|
6085
|
+
type
|
|
6086
|
+
status
|
|
6087
|
+
circleId
|
|
6088
|
+
userAddress
|
|
6089
|
+
usdcRecipientAddress
|
|
6090
|
+
acceptedMerchantAddress
|
|
6091
|
+
usdcAmount
|
|
6092
|
+
fiatAmount
|
|
6093
|
+
actualUsdcAmount
|
|
6094
|
+
actualFiatAmount
|
|
6095
|
+
currency
|
|
6096
|
+
placedAt
|
|
6097
|
+
acceptedAt
|
|
6098
|
+
paidAt
|
|
6099
|
+
completedAt
|
|
6100
|
+
fixedFeePaid
|
|
6101
|
+
tipsPaid
|
|
6102
|
+
disputeStatus
|
|
6103
|
+
}
|
|
6104
|
+
}
|
|
6105
|
+
`
|
|
6106
|
+
);
|
|
6107
|
+
|
|
6108
|
+
// src/orders/subgraph/index.ts
|
|
6109
|
+
function getOrdersForUser(subgraphUrl, userAddress, skip, limit, logger = noopLogger) {
|
|
6110
|
+
const user = userAddress.toLowerCase();
|
|
6111
|
+
logger.debug("fetching orders from subgraph", { subgraphUrl, user, skip, limit });
|
|
6112
|
+
return querySubgraph(subgraphUrl, {
|
|
6113
|
+
query: ORDERS_BY_USER_QUERY,
|
|
6114
|
+
variables: { user, skip, first: limit }
|
|
6115
|
+
}).mapErr(
|
|
6116
|
+
(e) => new OrdersError(e.message, {
|
|
6117
|
+
code: "SUBGRAPH_REQUEST_FAILED",
|
|
6118
|
+
cause: e.cause ?? e,
|
|
6119
|
+
context: { user, skip, limit, ...e.context ?? {} }
|
|
4531
6120
|
})
|
|
6121
|
+
).andThen(
|
|
6122
|
+
(data) => validate(
|
|
6123
|
+
ZodSubgraphOrdersResponseSchema,
|
|
6124
|
+
data,
|
|
6125
|
+
(message, cause, d) => new OrdersError(message, {
|
|
6126
|
+
code: "SUBGRAPH_VALIDATION_FAILED",
|
|
6127
|
+
cause,
|
|
6128
|
+
context: { data: d }
|
|
6129
|
+
})
|
|
6130
|
+
).andThen(
|
|
6131
|
+
(validated) => Result4.combine(validated.orders_collection.map(normalizeSubgraphOrder))
|
|
6132
|
+
)
|
|
4532
6133
|
);
|
|
4533
6134
|
}
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
6135
|
+
|
|
6136
|
+
// src/orders/watch-events.ts
|
|
6137
|
+
var PLACED_CONFIG = {
|
|
6138
|
+
eventName: "OrderPlaced",
|
|
6139
|
+
toEvent: (log) => ({
|
|
6140
|
+
type: "placed",
|
|
6141
|
+
orderId: log.args.orderId,
|
|
6142
|
+
user: log.args.user,
|
|
6143
|
+
orderType: log.args.orderType,
|
|
6144
|
+
blockNumber: log.blockNumber,
|
|
6145
|
+
txHash: log.transactionHash
|
|
6146
|
+
}),
|
|
6147
|
+
userFromLog: (log) => log.args.user
|
|
6148
|
+
};
|
|
6149
|
+
var ACCEPTED_CONFIG = {
|
|
6150
|
+
eventName: "OrderAccepted",
|
|
6151
|
+
toEvent: (log) => ({
|
|
6152
|
+
type: "accepted",
|
|
6153
|
+
orderId: log.args.orderId,
|
|
6154
|
+
merchant: log.args.merchant,
|
|
6155
|
+
blockNumber: log.blockNumber,
|
|
6156
|
+
txHash: log.transactionHash
|
|
6157
|
+
}),
|
|
6158
|
+
// OrderAccepted's top-level args are (orderId, merchant, pubKey, _order).
|
|
6159
|
+
// The buyer's address lives inside the _order tuple as _order.user.
|
|
6160
|
+
userFromLog: (log) => log.args._order?.user
|
|
6161
|
+
};
|
|
6162
|
+
var PAID_CONFIG = {
|
|
6163
|
+
eventName: "BuyOrderPaid",
|
|
6164
|
+
toEvent: (log) => ({
|
|
6165
|
+
type: "paid",
|
|
6166
|
+
orderId: log.args.orderId,
|
|
6167
|
+
blockNumber: log.blockNumber,
|
|
6168
|
+
txHash: log.transactionHash
|
|
6169
|
+
}),
|
|
6170
|
+
userFromLog: (log) => log.args.user
|
|
6171
|
+
};
|
|
6172
|
+
var COMPLETED_CONFIG = {
|
|
6173
|
+
eventName: "OrderCompleted",
|
|
6174
|
+
toEvent: (log) => ({
|
|
6175
|
+
type: "completed",
|
|
6176
|
+
orderId: log.args.orderId,
|
|
6177
|
+
blockNumber: log.blockNumber,
|
|
6178
|
+
txHash: log.transactionHash
|
|
6179
|
+
}),
|
|
6180
|
+
userFromLog: (log) => log.args.user
|
|
6181
|
+
};
|
|
6182
|
+
var CANCELLED_CONFIG = {
|
|
6183
|
+
eventName: "CancelledOrders",
|
|
6184
|
+
toEvent: (log) => ({
|
|
6185
|
+
type: "cancelled",
|
|
6186
|
+
orderId: log.args.orderId,
|
|
6187
|
+
blockNumber: log.blockNumber,
|
|
6188
|
+
txHash: log.transactionHash
|
|
6189
|
+
}),
|
|
6190
|
+
// CancelledOrders's top-level args are (orderId, _order). The buyer's
|
|
6191
|
+
// address lives inside the _order tuple as _order.user.
|
|
6192
|
+
userFromLog: (log) => log.args._order?.user
|
|
6193
|
+
};
|
|
6194
|
+
var ALL_CONFIGS = [
|
|
6195
|
+
PLACED_CONFIG,
|
|
6196
|
+
ACCEPTED_CONFIG,
|
|
6197
|
+
PAID_CONFIG,
|
|
6198
|
+
COMPLETED_CONFIG,
|
|
6199
|
+
CANCELLED_CONFIG
|
|
6200
|
+
];
|
|
6201
|
+
function createWatchEvents(input) {
|
|
6202
|
+
const { publicClient, diamondAddress } = input;
|
|
6203
|
+
return ({ user, onEvent, onError }) => {
|
|
6204
|
+
const unwatchers = [];
|
|
6205
|
+
for (const config of ALL_CONFIGS) {
|
|
6206
|
+
try {
|
|
6207
|
+
const unwatch = publicClient.watchContractEvent({
|
|
6208
|
+
address: diamondAddress,
|
|
6209
|
+
abi: ABIS.DIAMOND,
|
|
6210
|
+
eventName: config.eventName,
|
|
6211
|
+
onLogs: (logs) => {
|
|
6212
|
+
for (const log of logs) {
|
|
6213
|
+
if (user && config.userFromLog) {
|
|
6214
|
+
const logUser = config.userFromLog(log);
|
|
6215
|
+
if (!logUser || logUser.toLowerCase() !== user.toLowerCase()) continue;
|
|
6216
|
+
}
|
|
6217
|
+
onEvent(config.toEvent(log));
|
|
6218
|
+
}
|
|
6219
|
+
},
|
|
6220
|
+
onError: (err5) => {
|
|
6221
|
+
onError?.(
|
|
6222
|
+
new OrdersError(`watchContractEvent failed for ${config.eventName}`, {
|
|
6223
|
+
code: "EVENT_WATCH_FAILED",
|
|
6224
|
+
cause: err5,
|
|
6225
|
+
context: { eventName: config.eventName }
|
|
6226
|
+
})
|
|
6227
|
+
);
|
|
6228
|
+
}
|
|
6229
|
+
});
|
|
6230
|
+
unwatchers.push(unwatch);
|
|
6231
|
+
} catch (err5) {
|
|
6232
|
+
onError?.(
|
|
6233
|
+
new OrdersError(`failed to subscribe to ${config.eventName}`, {
|
|
6234
|
+
code: "EVENT_WATCH_FAILED",
|
|
6235
|
+
cause: err5,
|
|
6236
|
+
context: { eventName: config.eventName }
|
|
6237
|
+
})
|
|
6238
|
+
);
|
|
6239
|
+
}
|
|
6240
|
+
}
|
|
6241
|
+
return () => {
|
|
6242
|
+
for (const u of unwatchers) {
|
|
6243
|
+
try {
|
|
6244
|
+
u();
|
|
6245
|
+
} catch {
|
|
6246
|
+
}
|
|
6247
|
+
}
|
|
6248
|
+
};
|
|
6249
|
+
};
|
|
4549
6250
|
}
|
|
4550
6251
|
|
|
4551
|
-
// src/
|
|
4552
|
-
function
|
|
6252
|
+
// src/orders/client.ts
|
|
6253
|
+
function createOrders(config) {
|
|
6254
|
+
const { publicClient, diamondAddress, usdcAddress, subgraphUrl, relayIdentity } = config;
|
|
6255
|
+
const logger = config.logger ?? noopLogger;
|
|
6256
|
+
const relayIdentityStore = config.relayIdentityStore ?? createInMemoryRelayStore();
|
|
6257
|
+
const orderRouter = createOrderRouter({
|
|
6258
|
+
publicClient,
|
|
6259
|
+
subgraphUrl,
|
|
6260
|
+
contractAddress: diamondAddress,
|
|
6261
|
+
logger
|
|
6262
|
+
});
|
|
4553
6263
|
return {
|
|
4554
|
-
|
|
4555
|
-
|
|
6264
|
+
// ── Reads ─────────────────────────────────────────────────────────
|
|
6265
|
+
getOrder(params) {
|
|
6266
|
+
return validate(
|
|
6267
|
+
ZodGetOrderParamsSchema,
|
|
6268
|
+
params,
|
|
6269
|
+
(message, cause, d) => new OrdersError(message, {
|
|
6270
|
+
code: "INVALID_ORDER_ID",
|
|
6271
|
+
cause,
|
|
6272
|
+
context: { params: d }
|
|
6273
|
+
})
|
|
6274
|
+
).asyncAndThen(
|
|
6275
|
+
({ orderId }) => readOrderMulticall(publicClient, diamondAddress, orderId).mapErr(
|
|
6276
|
+
(cause) => new OrdersError("Order contract read failed", {
|
|
6277
|
+
code: "CONTRACT_READ_FAILED",
|
|
6278
|
+
cause,
|
|
6279
|
+
context: { orderId: orderId.toString() }
|
|
6280
|
+
})
|
|
6281
|
+
)
|
|
6282
|
+
).andThen(
|
|
6283
|
+
({ order, details }) => normalizeContractOrder(order, details).asyncAndThen((normalized) => {
|
|
6284
|
+
if (!normalized) {
|
|
6285
|
+
return errAsync4(
|
|
6286
|
+
new OrdersError("Order not found", {
|
|
6287
|
+
code: "ORDER_NOT_FOUND",
|
|
6288
|
+
context: { orderId: params.orderId.toString() }
|
|
6289
|
+
})
|
|
6290
|
+
);
|
|
6291
|
+
}
|
|
6292
|
+
logger.debug("getOrder resolved", { orderId: params.orderId.toString() });
|
|
6293
|
+
return okAsync4(normalized);
|
|
6294
|
+
})
|
|
6295
|
+
);
|
|
6296
|
+
},
|
|
6297
|
+
getOrders(params) {
|
|
6298
|
+
return validate(
|
|
6299
|
+
ZodGetOrdersParamsSchema,
|
|
6300
|
+
params,
|
|
6301
|
+
(message, cause, d) => new OrdersError(message, {
|
|
6302
|
+
code: "INVALID_GET_ORDERS_PARAMS",
|
|
6303
|
+
cause,
|
|
6304
|
+
context: { params: d }
|
|
6305
|
+
})
|
|
6306
|
+
).asyncAndThen(
|
|
6307
|
+
({ userAddress, skip, limit }) => getOrdersForUser(subgraphUrl, userAddress, skip, limit, logger)
|
|
6308
|
+
);
|
|
6309
|
+
},
|
|
6310
|
+
getFeeConfig(params) {
|
|
6311
|
+
return validate(
|
|
6312
|
+
ZodGetFeeConfigParamsSchema,
|
|
6313
|
+
params,
|
|
6314
|
+
(message, cause, d) => new OrdersError(message, {
|
|
6315
|
+
code: "INVALID_FEE_CONFIG_PARAMS",
|
|
6316
|
+
cause,
|
|
6317
|
+
context: { params: d }
|
|
6318
|
+
})
|
|
6319
|
+
).asyncAndThen(
|
|
6320
|
+
({ currency }) => readFeeConfigMulticall(publicClient, diamondAddress, currency).mapErr(
|
|
6321
|
+
(cause) => new OrdersError("Fee config contract read failed", {
|
|
6322
|
+
code: "CONTRACT_READ_FAILED",
|
|
6323
|
+
cause,
|
|
6324
|
+
context: { currency }
|
|
6325
|
+
})
|
|
6326
|
+
)
|
|
6327
|
+
).map((config2) => {
|
|
6328
|
+
logger.debug("getFeeConfig resolved", { currency: params.currency });
|
|
6329
|
+
return config2;
|
|
6330
|
+
});
|
|
6331
|
+
},
|
|
6332
|
+
// ── Writes ────────────────────────────────────────────────────────
|
|
6333
|
+
placeOrder: createPlaceOrderAction({
|
|
6334
|
+
publicClient,
|
|
6335
|
+
diamondAddress,
|
|
6336
|
+
orderRouter,
|
|
6337
|
+
relayIdentityStore,
|
|
6338
|
+
relayIdentity
|
|
6339
|
+
}),
|
|
6340
|
+
cancelOrder: createCancelOrderAction({ publicClient, diamondAddress }),
|
|
6341
|
+
setSellOrderUpi: createSetSellOrderUpiAction({
|
|
6342
|
+
publicClient,
|
|
6343
|
+
diamondAddress,
|
|
6344
|
+
relayIdentityStore,
|
|
6345
|
+
relayIdentity
|
|
6346
|
+
}),
|
|
6347
|
+
raiseDispute: createRaiseDisputeAction({ publicClient, diamondAddress }),
|
|
6348
|
+
approveUsdc: createApproveUsdcAction({ publicClient, diamondAddress, usdcAddress }),
|
|
6349
|
+
paidBuyOrder: createPaidBuyOrderAction({ publicClient, diamondAddress }),
|
|
6350
|
+
watchEvents: createWatchEvents({ publicClient, diamondAddress }),
|
|
6351
|
+
// ── Crypto helpers ───────────────────────────────────────────────
|
|
6352
|
+
decryptPaymentAddress({ encrypted }) {
|
|
6353
|
+
return resolveRelayIdentity({ relayIdentity, store: relayIdentityStore }).andThen(
|
|
6354
|
+
(recipientIdentity) => decryptPaymentAddress({ encrypted, recipientIdentity })
|
|
6355
|
+
);
|
|
4556
6356
|
},
|
|
4557
|
-
|
|
4558
|
-
return
|
|
6357
|
+
encryptPaymentAddress({ paymentAddress, recipientPublicKey }) {
|
|
6358
|
+
return resolveRelayIdentity({ relayIdentity, store: relayIdentityStore }).andThen(
|
|
6359
|
+
(senderIdentity) => encryptPaymentAddress({
|
|
6360
|
+
paymentAddress,
|
|
6361
|
+
recipientPublicKey,
|
|
6362
|
+
senderIdentity
|
|
6363
|
+
})
|
|
6364
|
+
);
|
|
4559
6365
|
}
|
|
4560
6366
|
};
|
|
4561
6367
|
}
|
|
4562
6368
|
|
|
6369
|
+
// src/prices/client.ts
|
|
6370
|
+
function createPrices(config) {
|
|
6371
|
+
const { publicClient, diamondAddress } = config;
|
|
6372
|
+
return {
|
|
6373
|
+
getPriceConfig: (params) => getPriceConfig(publicClient, diamondAddress, params),
|
|
6374
|
+
getReputationPerUsdcLimit: (params) => getReputationPerUsdcLimit(publicClient, diamondAddress, params)
|
|
6375
|
+
};
|
|
6376
|
+
}
|
|
6377
|
+
|
|
4563
6378
|
// src/profile/contracts/actions.ts
|
|
4564
|
-
import { ResultAsync as
|
|
6379
|
+
import { ResultAsync as ResultAsync11 } from "neverthrow";
|
|
4565
6380
|
import { formatUnits as formatUnits2 } from "viem";
|
|
4566
6381
|
function getBalances(publicClient, usdcAddress, diamondAddress, params) {
|
|
4567
6382
|
return validate(
|
|
@@ -4573,13 +6388,19 @@ function getBalances(publicClient, usdcAddress, diamondAddress, params) {
|
|
|
4573
6388
|
context: { params: data }
|
|
4574
6389
|
})
|
|
4575
6390
|
).asyncAndThen(
|
|
4576
|
-
(validated) =>
|
|
6391
|
+
(validated) => ResultAsync11.combine([
|
|
4577
6392
|
getUsdcBalance(publicClient, usdcAddress, {
|
|
4578
6393
|
address: validated.address
|
|
4579
6394
|
}),
|
|
4580
6395
|
getPriceConfig(publicClient, diamondAddress, {
|
|
4581
6396
|
currency: validated.currency
|
|
4582
|
-
})
|
|
6397
|
+
}).mapErr(
|
|
6398
|
+
(cause) => new ProfileError("Failed to read price config for balance conversion", {
|
|
6399
|
+
code: "CONTRACT_READ_ERROR",
|
|
6400
|
+
cause,
|
|
6401
|
+
context: { currency: validated.currency }
|
|
6402
|
+
})
|
|
6403
|
+
)
|
|
4583
6404
|
]).map(([usdc, priceConfig]) => {
|
|
4584
6405
|
const usdcFormatted = Number(formatUnits2(usdc, 6));
|
|
4585
6406
|
const sellPriceFormatted = Number(formatUnits2(priceConfig.sellPrice, 6));
|
|
@@ -4597,10 +6418,9 @@ function createProfile(config) {
|
|
|
4597
6418
|
const { publicClient, diamondAddress, usdcAddress } = config;
|
|
4598
6419
|
return {
|
|
4599
6420
|
getUsdcBalance: (params) => getUsdcBalance(publicClient, usdcAddress, params),
|
|
4600
|
-
|
|
6421
|
+
getUsdcAllowance: (params) => getUsdcAllowance(publicClient, usdcAddress, diamondAddress, params),
|
|
4601
6422
|
getBalances: (params) => getBalances(publicClient, usdcAddress, diamondAddress, params),
|
|
4602
|
-
getTxLimits: (params) => getTxLimits(publicClient, diamondAddress, params)
|
|
4603
|
-
getRpPerUsdtLimitRational: (params) => getRpPerUsdtLimitRational(publicClient, diamondAddress, params)
|
|
6423
|
+
getTxLimits: (params) => getTxLimits(publicClient, diamondAddress, params)
|
|
4604
6424
|
};
|
|
4605
6425
|
}
|
|
4606
6426
|
|
|
@@ -4641,21 +6461,28 @@ function SdkProvider({ children, ...config }) {
|
|
|
4641
6461
|
initedRef.current = fraudEngine;
|
|
4642
6462
|
fraudEngine.init();
|
|
4643
6463
|
}, [fraudEngine]);
|
|
6464
|
+
const relayIdentityStore = config.orders?.relayIdentityStore;
|
|
6465
|
+
const relayIdentity = config.orders?.relayIdentity;
|
|
4644
6466
|
const sdk = useMemo(() => {
|
|
4645
|
-
const orderRouter = createOrderRouter({
|
|
4646
|
-
publicClient,
|
|
4647
|
-
subgraphUrl: config.subgraphUrl,
|
|
4648
|
-
contractAddress: config.diamondAddress,
|
|
4649
|
-
logger
|
|
4650
|
-
});
|
|
4651
6467
|
return {
|
|
4652
6468
|
profile: createProfile({
|
|
4653
6469
|
publicClient,
|
|
4654
6470
|
diamondAddress: config.diamondAddress,
|
|
4655
6471
|
usdcAddress: config.usdcAddress
|
|
4656
6472
|
}),
|
|
4657
|
-
|
|
4658
|
-
|
|
6473
|
+
prices: createPrices({
|
|
6474
|
+
publicClient,
|
|
6475
|
+
diamondAddress: config.diamondAddress
|
|
6476
|
+
}),
|
|
6477
|
+
orders: createOrders({
|
|
6478
|
+
publicClient,
|
|
6479
|
+
diamondAddress: config.diamondAddress,
|
|
6480
|
+
usdcAddress: config.usdcAddress,
|
|
6481
|
+
subgraphUrl: config.subgraphUrl,
|
|
6482
|
+
relayIdentityStore,
|
|
6483
|
+
relayIdentity,
|
|
6484
|
+
logger
|
|
6485
|
+
}),
|
|
4659
6486
|
zkkyc: config.reputationManagerAddress ? createZkkyc({
|
|
4660
6487
|
reputationManagerAddress: config.reputationManagerAddress
|
|
4661
6488
|
}) : void 0,
|
|
@@ -4667,6 +6494,8 @@ function SdkProvider({ children, ...config }) {
|
|
|
4667
6494
|
config.diamondAddress,
|
|
4668
6495
|
config.usdcAddress,
|
|
4669
6496
|
config.reputationManagerAddress,
|
|
6497
|
+
relayIdentityStore,
|
|
6498
|
+
relayIdentity,
|
|
4670
6499
|
logger,
|
|
4671
6500
|
fraudEngine
|
|
4672
6501
|
]);
|
|
@@ -4682,11 +6511,11 @@ function useSdk() {
|
|
|
4682
6511
|
function useProfile() {
|
|
4683
6512
|
return useSdk().profile;
|
|
4684
6513
|
}
|
|
4685
|
-
function
|
|
4686
|
-
return useSdk().
|
|
6514
|
+
function usePrices() {
|
|
6515
|
+
return useSdk().prices;
|
|
4687
6516
|
}
|
|
4688
|
-
function
|
|
4689
|
-
return useSdk().
|
|
6517
|
+
function useOrders() {
|
|
6518
|
+
return useSdk().orders;
|
|
4690
6519
|
}
|
|
4691
6520
|
function useZkkyc() {
|
|
4692
6521
|
const zkkyc = useSdk().zkkyc;
|
|
@@ -4703,13 +6532,32 @@ function useFraudEngine() {
|
|
|
4703
6532
|
return fraudEngine;
|
|
4704
6533
|
}
|
|
4705
6534
|
|
|
6535
|
+
// src/react/use-watch-orders.ts
|
|
6536
|
+
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
6537
|
+
function useWatchOrders(params) {
|
|
6538
|
+
const orders = useOrders();
|
|
6539
|
+
const { user, onEvent, onError } = params;
|
|
6540
|
+
const onEventRef = useRef2(onEvent);
|
|
6541
|
+
const onErrorRef = useRef2(onError);
|
|
6542
|
+
onEventRef.current = onEvent;
|
|
6543
|
+
onErrorRef.current = onError;
|
|
6544
|
+
useEffect2(() => {
|
|
6545
|
+
const unsubscribe = orders.watchEvents({
|
|
6546
|
+
user,
|
|
6547
|
+
onEvent: (event) => onEventRef.current(event),
|
|
6548
|
+
onError: (error) => onErrorRef.current?.(error)
|
|
6549
|
+
});
|
|
6550
|
+
return unsubscribe;
|
|
6551
|
+
}, [orders, user]);
|
|
6552
|
+
}
|
|
6553
|
+
|
|
4706
6554
|
// src/fraud-engine/react/use-fingerprint.ts
|
|
4707
|
-
import { useEffect as
|
|
6555
|
+
import { useEffect as useEffect3, useState } from "react";
|
|
4708
6556
|
function useFingerprint(enabled) {
|
|
4709
6557
|
const [data, setData] = useState(null);
|
|
4710
6558
|
const [error, setError] = useState(null);
|
|
4711
6559
|
const [isLoading, setIsLoading] = useState(false);
|
|
4712
|
-
|
|
6560
|
+
useEffect3(() => {
|
|
4713
6561
|
if (!enabled) return;
|
|
4714
6562
|
let cancelled = false;
|
|
4715
6563
|
setIsLoading(true);
|
|
@@ -4740,10 +6588,11 @@ export {
|
|
|
4740
6588
|
SdkProvider,
|
|
4741
6589
|
useFingerprint,
|
|
4742
6590
|
useFraudEngine,
|
|
4743
|
-
|
|
4744
|
-
|
|
6591
|
+
useOrders,
|
|
6592
|
+
usePrices,
|
|
4745
6593
|
useProfile,
|
|
4746
6594
|
useSdk,
|
|
6595
|
+
useWatchOrders,
|
|
4747
6596
|
useZkkyc
|
|
4748
6597
|
};
|
|
4749
6598
|
/*! Bundled license information:
|