@oasisprotocol/privana-sdk 0.4.0 → 0.4.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/dist/{chunk-RDMJGMI3.cjs → chunk-CRJNDCDT.cjs} +19 -3
- package/dist/chunk-CRJNDCDT.cjs.map +1 -0
- package/dist/{chunk-ZVNC4FTJ.js → chunk-ZXFQJ5MG.js} +19 -4
- package/dist/chunk-ZXFQJ5MG.js.map +1 -0
- package/dist/index.cjs +150 -157
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +3 -13
- package/dist/index.js.map +1 -1
- package/dist/on-ramp.cjs +149 -52
- package/dist/on-ramp.cjs.map +1 -1
- package/dist/on-ramp.d.cts +6 -0
- package/dist/on-ramp.d.ts +6 -0
- package/dist/on-ramp.js +146 -49
- package/dist/on-ramp.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-RDMJGMI3.cjs.map +0 -1
- package/dist/chunk-ZVNC4FTJ.js.map +0 -1
package/dist/on-ramp.cjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkCRJNDCDT_cjs = require('./chunk-CRJNDCDT.cjs');
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var viem = require('viem');
|
|
7
7
|
var wagmi = require('wagmi');
|
|
8
|
+
var lucideReact = require('lucide-react');
|
|
8
9
|
var moonpayReact = require('@moonpay/moonpay-react');
|
|
9
10
|
var jsxRuntime = require('react/jsx-runtime');
|
|
10
11
|
|
|
@@ -20,8 +21,8 @@ function useFiatOnRamp(options) {
|
|
|
20
21
|
const deliveryPollInterval = options.deliveryPollInterval ?? 3e3;
|
|
21
22
|
const verificationTimeout = options.verificationTimeout ?? DEFAULT_VERIFICATION_TIMEOUT_MS;
|
|
22
23
|
const finalityRetryInterval = options.finalityRetryInterval ?? DEFAULT_FINALITY_RETRY_INTERVAL_MS;
|
|
23
|
-
const { client, enabledTokens } =
|
|
24
|
-
const { executePrivateRead, privateReadReady } =
|
|
24
|
+
const { client, enabledTokens } = chunkCRJNDCDT_cjs.usePrivanaContext();
|
|
25
|
+
const { executePrivateRead, privateReadReady } = chunkCRJNDCDT_cjs.usePrivateReadRequest();
|
|
25
26
|
const wagmiConfig = wagmi.useConfig();
|
|
26
27
|
const selectedToken = enabledTokens.find((t) => t.id.toLowerCase() === tokenId.toLowerCase());
|
|
27
28
|
const [status, setStatus] = react.useState("idle");
|
|
@@ -30,6 +31,7 @@ function useFiatOnRamp(options) {
|
|
|
30
31
|
const [depositAddress, setDepositAddress] = react.useState();
|
|
31
32
|
const [minDepositBaseUnits, setMinDepositBaseUnits] = react.useState();
|
|
32
33
|
const [activeIntentId, setActiveIntentId] = react.useState(null);
|
|
34
|
+
const [finalityProgress, setFinalityProgress] = react.useState({});
|
|
33
35
|
const onCreditedRef = react.useRef(onCredited);
|
|
34
36
|
const onErrorRef = react.useRef(onError);
|
|
35
37
|
const onDebugEventRef = react.useRef(onDebugEvent);
|
|
@@ -39,6 +41,7 @@ function useFiatOnRamp(options) {
|
|
|
39
41
|
const activeVerificationKeyRef = react.useRef(null);
|
|
40
42
|
const triggeredVerificationKeysRef = react.useRef(/* @__PURE__ */ new Set());
|
|
41
43
|
const closeReconcilePromiseRef = react.useRef(null);
|
|
44
|
+
const purchaseInitiatedRef = react.useRef(false);
|
|
42
45
|
react.useEffect(() => {
|
|
43
46
|
onCreditedRef.current = onCredited;
|
|
44
47
|
onErrorRef.current = onError;
|
|
@@ -130,17 +133,36 @@ function useFiatOnRamp(options) {
|
|
|
130
133
|
activeVerificationKeyRef.current = null;
|
|
131
134
|
activeVerificationRecordRef.current = null;
|
|
132
135
|
}, []);
|
|
133
|
-
const { verify } =
|
|
136
|
+
const { verify } = chunkCRJNDCDT_cjs.useDepositVerification({
|
|
134
137
|
pollTimeout: verificationTimeout,
|
|
135
138
|
pollInterval: options.verificationPollInterval,
|
|
136
139
|
finalityRetryInterval,
|
|
140
|
+
onCheckRetry: (message) => {
|
|
141
|
+
const record = activeVerificationRecordRef.current;
|
|
142
|
+
if (!record) return;
|
|
143
|
+
emitDebug("verification:check-retry", {
|
|
144
|
+
message,
|
|
145
|
+
record: summariseOnRampRecord(record)
|
|
146
|
+
});
|
|
147
|
+
setFinalityProgress((prev) => ({ ...prev, [record.transaction_id]: message }));
|
|
148
|
+
},
|
|
137
149
|
onCredited: (depositTxHash) => {
|
|
138
150
|
const record = activeVerificationRecordRef.current;
|
|
139
151
|
emitDebug("verification:credited", {
|
|
140
152
|
depositTxHash,
|
|
141
153
|
record: record ? summariseOnRampRecord(record) : null
|
|
142
154
|
});
|
|
143
|
-
|
|
155
|
+
if (record && activeIntentIdRef.current === record.transaction_id) {
|
|
156
|
+
setStatus("credited");
|
|
157
|
+
}
|
|
158
|
+
if (record) {
|
|
159
|
+
setFinalityProgress((prev) => {
|
|
160
|
+
if (!(record.transaction_id in prev)) return prev;
|
|
161
|
+
const next = { ...prev };
|
|
162
|
+
delete next[record.transaction_id];
|
|
163
|
+
return next;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
144
166
|
void (async () => {
|
|
145
167
|
try {
|
|
146
168
|
if (record && depositTxHash.startsWith("0x")) {
|
|
@@ -172,21 +194,27 @@ function useFiatOnRamp(options) {
|
|
|
172
194
|
onCreditedRef.current?.(depositTxHash);
|
|
173
195
|
},
|
|
174
196
|
onCheckTimeout: (depositTxHash) => {
|
|
197
|
+
const record = activeVerificationRecordRef.current;
|
|
175
198
|
const err = new Error(
|
|
176
199
|
"Privana verification is still pending. Retry from the pending on-ramp list if it does not complete."
|
|
177
200
|
);
|
|
178
201
|
emitDebug("verification:timeout", { depositTxHash, message: err.message });
|
|
179
202
|
clearActiveVerification();
|
|
180
|
-
|
|
181
|
-
|
|
203
|
+
if (!record || activeIntentIdRef.current === record.transaction_id) {
|
|
204
|
+
setStatus("failed");
|
|
205
|
+
setError(err);
|
|
206
|
+
}
|
|
182
207
|
void refreshPending();
|
|
183
208
|
onErrorRef.current?.(err);
|
|
184
209
|
},
|
|
185
210
|
onError: (err) => {
|
|
211
|
+
const record = activeVerificationRecordRef.current;
|
|
186
212
|
emitDebug("verification:error", errorPayload(err));
|
|
187
213
|
clearActiveVerification();
|
|
188
|
-
|
|
189
|
-
|
|
214
|
+
if (!record || activeIntentIdRef.current === record.transaction_id) {
|
|
215
|
+
setStatus("failed");
|
|
216
|
+
setError(err);
|
|
217
|
+
}
|
|
190
218
|
onErrorRef.current?.(err);
|
|
191
219
|
}
|
|
192
220
|
});
|
|
@@ -198,6 +226,7 @@ function useFiatOnRamp(options) {
|
|
|
198
226
|
}) => {
|
|
199
227
|
try {
|
|
200
228
|
setError(null);
|
|
229
|
+
purchaseInitiatedRef.current = false;
|
|
201
230
|
const token = enabledTokens.find((t) => t.id.toLowerCase() === tokenId.toLowerCase());
|
|
202
231
|
if (!token) throw new Error(`Unknown token: ${tokenId}`);
|
|
203
232
|
if (!depositAddress) throw new Error("Privana deposit address is not ready");
|
|
@@ -280,6 +309,7 @@ function useFiatOnRamp(options) {
|
|
|
280
309
|
const handleTransactionCreated = react.useCallback(
|
|
281
310
|
async (props) => {
|
|
282
311
|
emitDebug("moonpay:onTransactionCreated", summariseMoonPayEventProps(props));
|
|
312
|
+
purchaseInitiatedRef.current = true;
|
|
283
313
|
await registerOnRampTokenMapping(props.id);
|
|
284
314
|
},
|
|
285
315
|
[emitDebug, registerOnRampTokenMapping]
|
|
@@ -358,6 +388,12 @@ function useFiatOnRamp(options) {
|
|
|
358
388
|
triggeredVerificationKeysRef.current.add(verificationKey);
|
|
359
389
|
activeVerificationKeyRef.current = verificationKey;
|
|
360
390
|
activeVerificationRecordRef.current = record;
|
|
391
|
+
setFinalityProgress((prev) => {
|
|
392
|
+
if (!(record.transaction_id in prev)) return prev;
|
|
393
|
+
const next = { ...prev };
|
|
394
|
+
delete next[record.transaction_id];
|
|
395
|
+
return next;
|
|
396
|
+
});
|
|
361
397
|
emitDebug("verification:start", {
|
|
362
398
|
verificationKey,
|
|
363
399
|
record: summariseOnRampRecord(record)
|
|
@@ -398,7 +434,9 @@ function useFiatOnRamp(options) {
|
|
|
398
434
|
`Delivered amount (${record.quote_currency_amount}) is below the minimum deposit.`
|
|
399
435
|
);
|
|
400
436
|
}
|
|
401
|
-
|
|
437
|
+
if (activeIntentIdRef.current === record.transaction_id) {
|
|
438
|
+
setStatus("verifying");
|
|
439
|
+
}
|
|
402
440
|
emitDebug("verification:check-deposit-request", {
|
|
403
441
|
hash: record.on_chain_tx_hash,
|
|
404
442
|
chainId: record.chain_id,
|
|
@@ -466,6 +504,17 @@ function useFiatOnRamp(options) {
|
|
|
466
504
|
await refreshPending();
|
|
467
505
|
return;
|
|
468
506
|
}
|
|
507
|
+
if (!purchaseInitiatedRef.current) {
|
|
508
|
+
emitDebug("moonpay:widget-closed-without-purchase", {
|
|
509
|
+
previousStatus,
|
|
510
|
+
transactionId
|
|
511
|
+
});
|
|
512
|
+
await refreshPending();
|
|
513
|
+
if (previousStatus === "awaiting-purchase" || previousStatus === "awaiting-delivery") {
|
|
514
|
+
setStatus("idle");
|
|
515
|
+
}
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
469
518
|
try {
|
|
470
519
|
setStatus("awaiting-delivery");
|
|
471
520
|
const record = await waitForOnChainHash(transactionId);
|
|
@@ -504,15 +553,39 @@ function useFiatOnRamp(options) {
|
|
|
504
553
|
setStatus("failed");
|
|
505
554
|
setError(e);
|
|
506
555
|
onErrorRef.current?.(e);
|
|
556
|
+
throw e;
|
|
507
557
|
}
|
|
508
558
|
},
|
|
509
559
|
[emitDebug, triggerVerification]
|
|
510
560
|
);
|
|
561
|
+
const triggerVerificationRef = react.useRef(triggerVerification);
|
|
562
|
+
react.useEffect(() => {
|
|
563
|
+
triggerVerificationRef.current = triggerVerification;
|
|
564
|
+
}, [triggerVerification]);
|
|
565
|
+
react.useEffect(() => {
|
|
566
|
+
let cancelled = false;
|
|
567
|
+
void (async () => {
|
|
568
|
+
for (const record of pending) {
|
|
569
|
+
if (cancelled) break;
|
|
570
|
+
if (!record.on_chain_tx_hash || !record.quote_currency_amount) continue;
|
|
571
|
+
const key = getOnRampVerificationKey(record);
|
|
572
|
+
if (triggeredVerificationKeysRef.current.has(key)) continue;
|
|
573
|
+
try {
|
|
574
|
+
await triggerVerificationRef.current(record);
|
|
575
|
+
} catch {
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
})();
|
|
579
|
+
return () => {
|
|
580
|
+
cancelled = true;
|
|
581
|
+
};
|
|
582
|
+
}, [pending]);
|
|
511
583
|
return {
|
|
512
584
|
status,
|
|
513
585
|
activeIntentId,
|
|
514
586
|
pending,
|
|
515
587
|
error,
|
|
588
|
+
finalityProgress,
|
|
516
589
|
depositAddress,
|
|
517
590
|
minDepositBaseUnits,
|
|
518
591
|
selectedToken,
|
|
@@ -564,9 +637,11 @@ async function resolveDeliveredAmount({
|
|
|
564
637
|
}
|
|
565
638
|
let receiptError;
|
|
566
639
|
try {
|
|
567
|
-
const receipt = await
|
|
640
|
+
const receipt = await chunkCRJNDCDT_cjs.waitForTransactionReceipt(wagmiConfig, {
|
|
568
641
|
hash: onChainTxHash,
|
|
569
|
-
chainId
|
|
642
|
+
chainId,
|
|
643
|
+
timeout: 6e4,
|
|
644
|
+
pollingInterval: 4e3
|
|
570
645
|
});
|
|
571
646
|
let delivered = 0n;
|
|
572
647
|
for (const log of receipt.logs) {
|
|
@@ -671,11 +746,13 @@ function FiatOnRampForm({
|
|
|
671
746
|
const { address } = wagmi.useAccount();
|
|
672
747
|
const [visible, setVisible] = react.useState(false);
|
|
673
748
|
const [isPreparing, setIsPreparing] = react.useState(false);
|
|
749
|
+
const [rowError, setRowError] = react.useState(null);
|
|
674
750
|
const {
|
|
675
751
|
status,
|
|
676
752
|
activeIntentId,
|
|
677
753
|
pending,
|
|
678
754
|
error,
|
|
755
|
+
finalityProgress,
|
|
679
756
|
depositAddress,
|
|
680
757
|
minDepositBaseUnits,
|
|
681
758
|
selectedToken,
|
|
@@ -702,15 +779,17 @@ function FiatOnRampForm({
|
|
|
702
779
|
);
|
|
703
780
|
const minFiatGate = minDepositBaseUnits !== void 0 && decimals !== void 0 ? Number(viem.formatUnits(minDepositBaseUnits, decimals)) * 1.05 : void 0;
|
|
704
781
|
const isBelowMin = minFiatGate !== void 0 && Number(defaultBaseCurrencyAmount) < minFiatGate;
|
|
705
|
-
const isBusy = isPreparing || status === "awaiting-purchase"
|
|
782
|
+
const isBusy = isPreparing || status === "awaiting-purchase";
|
|
783
|
+
const isInitializing = !!address && !depositAddress;
|
|
706
784
|
const blockReasons = react.useMemo(
|
|
707
785
|
() => [
|
|
708
786
|
!address ? "wallet-not-connected" : null,
|
|
709
787
|
!depositAddress ? "deposit-address-not-loaded" : null,
|
|
710
788
|
isBusy ? `busy:${isPreparing ? "preparing" : status}` : null,
|
|
789
|
+
visible ? "widget-open" : null,
|
|
711
790
|
isBelowMin ? "below-minimum" : null
|
|
712
791
|
].filter((reason) => Boolean(reason)),
|
|
713
|
-
[address, depositAddress, isBelowMin, isBusy, isPreparing, status]
|
|
792
|
+
[address, depositAddress, isBelowMin, isBusy, isPreparing, status, visible]
|
|
714
793
|
);
|
|
715
794
|
const canBuy = blockReasons.length === 0;
|
|
716
795
|
const handleOpen = react.useCallback(async () => {
|
|
@@ -785,11 +864,10 @@ function FiatOnRampForm({
|
|
|
785
864
|
const handleReady = react.useCallback(async () => {
|
|
786
865
|
emitFormDebug("moonpay:onReady");
|
|
787
866
|
}, [emitFormDebug]);
|
|
788
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
789
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
790
|
-
|
|
791
|
-
"
|
|
792
|
-
blockReasons.join(", ")
|
|
867
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-privana": true, className: "flex flex-col gap-4", children: [
|
|
868
|
+
isInitializing ? /* @__PURE__ */ jsxRuntime.jsx(chunkCRJNDCDT_cjs.Skeleton, { className: "h-9 w-full rounded-md" }) : /* @__PURE__ */ jsxRuntime.jsxs(chunkCRJNDCDT_cjs.Button, { type: "button", onClick: handleOpen, disabled: !canBuy, children: [
|
|
869
|
+
(isBusy || visible) && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "animate-spin", "aria-hidden": true }),
|
|
870
|
+
"Buy"
|
|
793
871
|
] }),
|
|
794
872
|
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-destructive text-sm", role: "alert", children: error.message }),
|
|
795
873
|
isBelowMin && minFiatGate !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-destructive text-sm", role: "alert", children: [
|
|
@@ -798,24 +876,54 @@ function FiatOnRampForm({
|
|
|
798
876
|
"."
|
|
799
877
|
] }),
|
|
800
878
|
pending.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-3", children: [
|
|
801
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: "
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
879
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: "Pending payments" }),
|
|
880
|
+
pending.map((record) => {
|
|
881
|
+
const progress = parseFinalityProgress(finalityProgress[record.transaction_id]);
|
|
882
|
+
const hasProgress = !!finalityProgress[record.transaction_id];
|
|
883
|
+
const isStalled = !hasProgress && Date.now() / 1e3 - (record.updated_at ?? 0) > 60;
|
|
884
|
+
const showRetry = rowError?.id === record.transaction_id || isStalled;
|
|
885
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
886
|
+
"div",
|
|
887
|
+
{
|
|
888
|
+
className: "border-border flex flex-col gap-1 rounded-md border p-2",
|
|
889
|
+
children: [
|
|
890
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
891
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground flex items-center gap-1 text-xs", children: [
|
|
892
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3 animate-spin", "aria-hidden": true }),
|
|
893
|
+
progress ?? "Verifying\u2026"
|
|
894
|
+
] }),
|
|
895
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground text-xs", children: [
|
|
896
|
+
record.quote_currency_amount ?? "?",
|
|
897
|
+
" ",
|
|
898
|
+
displaySymbol
|
|
899
|
+
] })
|
|
900
|
+
] }),
|
|
901
|
+
rowError?.id === record.transaction_id && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-destructive text-xs", children: rowError.message }),
|
|
902
|
+
showRetry && /* @__PURE__ */ jsxRuntime.jsx(
|
|
903
|
+
chunkCRJNDCDT_cjs.Button,
|
|
904
|
+
{
|
|
905
|
+
type: "button",
|
|
906
|
+
variant: "outline",
|
|
907
|
+
size: "sm",
|
|
908
|
+
onClick: async () => {
|
|
909
|
+
setRowError(null);
|
|
910
|
+
try {
|
|
911
|
+
await finishPendingVerification(record);
|
|
912
|
+
} catch (err) {
|
|
913
|
+
setRowError({
|
|
914
|
+
id: record.transaction_id,
|
|
915
|
+
message: err instanceof Error ? err.message : "Verification failed"
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
},
|
|
919
|
+
children: "Retry"
|
|
920
|
+
}
|
|
921
|
+
)
|
|
922
|
+
]
|
|
923
|
+
},
|
|
924
|
+
record.transaction_id
|
|
925
|
+
);
|
|
926
|
+
})
|
|
819
927
|
] }),
|
|
820
928
|
visible && depositAddress && activeIntentId && /* @__PURE__ */ jsxRuntime.jsx(
|
|
821
929
|
moonpayReact.MoonPayBuyWidget,
|
|
@@ -838,21 +946,10 @@ function FiatOnRampForm({
|
|
|
838
946
|
)
|
|
839
947
|
] });
|
|
840
948
|
}
|
|
841
|
-
function
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
case "awaiting-delivery":
|
|
846
|
-
return "Waiting for on-chain delivery\u2026";
|
|
847
|
-
case "verifying":
|
|
848
|
-
return "Verifying with Privana\u2026";
|
|
849
|
-
case "credited":
|
|
850
|
-
return "Credited";
|
|
851
|
-
case "failed":
|
|
852
|
-
return "Failed";
|
|
853
|
-
default:
|
|
854
|
-
return "";
|
|
855
|
-
}
|
|
949
|
+
function parseFinalityProgress(message) {
|
|
950
|
+
if (!message) return null;
|
|
951
|
+
const match = message.match(/(\d+\/\d+)\s+confirmations/i);
|
|
952
|
+
return match ? `${match[1]} confirmations` : null;
|
|
856
953
|
}
|
|
857
954
|
|
|
858
955
|
exports.FiatOnRampForm = FiatOnRampForm;
|