@oasisprotocol/privana-sdk 0.5.0 → 0.5.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-ACLJPC75.cjs → chunk-4IW4V7YJ.cjs} +929 -20
- package/dist/chunk-4IW4V7YJ.cjs.map +1 -0
- package/dist/{chunk-54FC6TO3.js → chunk-SAJ7K5WT.js} +900 -22
- package/dist/chunk-SAJ7K5WT.js.map +1 -0
- package/dist/index.cjs +711 -506
- 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 +56 -339
- package/dist/index.d.ts +56 -339
- package/dist/index.js +419 -301
- package/dist/index.js.map +1 -1
- package/dist/on-ramp.cjs +3 -3
- package/dist/on-ramp.d.cts +40 -4
- package/dist/on-ramp.d.ts +40 -4
- package/dist/on-ramp.js +1 -1
- package/dist/pending-lock-BdkuMjmY.d.cts +600 -0
- package/dist/pending-lock-BdkuMjmY.d.ts +600 -0
- package/package.json +1 -1
- package/dist/chunk-54FC6TO3.js.map +0 -1
- package/dist/chunk-ACLJPC75.cjs.map +0 -1
- package/dist/on-ramp-XLXsy0aI.d.cts +0 -130
- package/dist/on-ramp-XLXsy0aI.d.ts +0 -130
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { createContext, useContext, useRef, useCallback, useSyncExternalStore, useState, useEffect, useMemo } from 'react';
|
|
3
|
-
import { WagmiContext, useConfig, useAccount } from 'wagmi';
|
|
3
|
+
import { WagmiContext, useConfig, useChainId, useSwitchChain, useAccount, useWalletClient } from 'wagmi';
|
|
4
4
|
import { watchAccount, getAccount, getWalletClient } from 'wagmi/actions';
|
|
5
5
|
import { createSiweMessage } from 'viem/siwe';
|
|
6
6
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
|
-
import { parseAbiItem, zeroAddress, hexToString, parseUnits, decodeEventLog, formatUnits } from 'viem';
|
|
7
|
+
import { parseAbiItem, zeroAddress, walletActions, hexToString, parseUnits, decodeEventLog, formatUnits, createClient, custom } from 'viem';
|
|
8
8
|
import { useQueryClient } from '@tanstack/react-query';
|
|
9
9
|
import { Slot } from '@radix-ui/react-slot';
|
|
10
10
|
import { cva } from 'class-variance-authority';
|
|
11
11
|
import { clsx } from 'clsx';
|
|
12
12
|
import { twMerge } from 'tailwind-merge';
|
|
13
|
+
import { parseAccount, getAddress } from 'viem/utils';
|
|
13
14
|
import { getTransactionReceipt as getTransactionReceipt$1, waitForTransactionReceipt as waitForTransactionReceipt$1, getTransaction, call } from 'viem/actions';
|
|
14
15
|
import { Loader2, CircleCheckIcon } from 'lucide-react';
|
|
15
16
|
import { MoonPayBuyWidget } from '@moonpay/moonpay-react';
|
|
@@ -34,7 +35,7 @@ var config_default = {
|
|
|
34
35
|
testnet: {
|
|
35
36
|
chainId: 23295,
|
|
36
37
|
name: "Sapphire Testnet",
|
|
37
|
-
accountingContract: "
|
|
38
|
+
accountingContract: "0xad3C76e4E621C0cfF7540479Ee9B0A945723A642",
|
|
38
39
|
apiUrl: "https://api.testnet.privana.finance"
|
|
39
40
|
},
|
|
40
41
|
mainnet: {
|
|
@@ -372,6 +373,19 @@ var PrivanaClient = class {
|
|
|
372
373
|
async getDepositStatus(depositId) {
|
|
373
374
|
return this.http.get(`/v1/accounting/deposits/status/${depositId}`);
|
|
374
375
|
}
|
|
376
|
+
async getPendingDeposits(request) {
|
|
377
|
+
const params = new URLSearchParams({ chain_id: String(request.chain_id) });
|
|
378
|
+
if (request.version !== void 0) params.set("version", String(request.version));
|
|
379
|
+
if (request.token_address !== void 0) {
|
|
380
|
+
params.set("token_address", normalizeAddress(request.token_address));
|
|
381
|
+
}
|
|
382
|
+
if (request.lookback_blocks !== void 0) {
|
|
383
|
+
params.set("lookback_blocks", String(request.lookback_blocks));
|
|
384
|
+
}
|
|
385
|
+
return this.http.get(
|
|
386
|
+
`/v1/accounting/deposits/pending?${params.toString()}`
|
|
387
|
+
);
|
|
388
|
+
}
|
|
375
389
|
async getBalance(tokenId) {
|
|
376
390
|
const token = normalizeHex(tokenId);
|
|
377
391
|
return this.http.get(`/v1/accounting/balances/${token}`);
|
|
@@ -623,6 +637,202 @@ var PrivanaClient = class {
|
|
|
623
637
|
this.http.removeHeader("Authorization");
|
|
624
638
|
}
|
|
625
639
|
};
|
|
640
|
+
|
|
641
|
+
// src/sdk/signatures/eip712-types.ts
|
|
642
|
+
function createDomain(chainId, verifyingContract) {
|
|
643
|
+
return {
|
|
644
|
+
name: "AccountingModule",
|
|
645
|
+
version: "1",
|
|
646
|
+
chainId,
|
|
647
|
+
verifyingContract
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
var LOCK_TYPES = {
|
|
651
|
+
Lock: [
|
|
652
|
+
{ name: "serviceAddress", type: "address" },
|
|
653
|
+
{ name: "tokenId", type: "bytes32" },
|
|
654
|
+
{ name: "amount", type: "uint256" },
|
|
655
|
+
{ name: "expiry", type: "uint256" },
|
|
656
|
+
{ name: "nonce", type: "uint256" }
|
|
657
|
+
]
|
|
658
|
+
};
|
|
659
|
+
var TRANSFER_TYPES = {
|
|
660
|
+
Transfer: [
|
|
661
|
+
{ name: "toAddress", type: "address" },
|
|
662
|
+
{ name: "tokenId", type: "bytes32" },
|
|
663
|
+
{ name: "amount", type: "uint256" },
|
|
664
|
+
{ name: "nonce", type: "uint256" }
|
|
665
|
+
]
|
|
666
|
+
};
|
|
667
|
+
var TRANSFER_LOCKED_TYPES = {
|
|
668
|
+
TransferLocked: [
|
|
669
|
+
{ name: "userAddress", type: "address" },
|
|
670
|
+
{ name: "toAddress", type: "address" },
|
|
671
|
+
{ name: "lockId", type: "uint256" },
|
|
672
|
+
{ name: "amount", type: "uint256" },
|
|
673
|
+
{ name: "nonce", type: "uint256" },
|
|
674
|
+
{ name: "serviceAddress", type: "address" }
|
|
675
|
+
]
|
|
676
|
+
};
|
|
677
|
+
var WITHDRAW_TYPES = {
|
|
678
|
+
Withdraw: [
|
|
679
|
+
{ name: "tokenId", type: "bytes32" },
|
|
680
|
+
{ name: "amount", type: "uint256" },
|
|
681
|
+
{ name: "nonce", type: "uint256" }
|
|
682
|
+
]
|
|
683
|
+
};
|
|
684
|
+
var MODIFY_LOCK_TYPES = {
|
|
685
|
+
ModifyLock: [
|
|
686
|
+
{ name: "lockId", type: "uint256" },
|
|
687
|
+
{ name: "amount", type: "uint256" },
|
|
688
|
+
{ name: "newExpiry", type: "uint256" },
|
|
689
|
+
{ name: "nonce", type: "uint256" }
|
|
690
|
+
]
|
|
691
|
+
};
|
|
692
|
+
var WITHDRAW_FROM_LOCK_TYPES = {
|
|
693
|
+
WithdrawFromLock: [
|
|
694
|
+
{ name: "userAddress", type: "address" },
|
|
695
|
+
{ name: "toAddress", type: "address" },
|
|
696
|
+
{ name: "lockId", type: "uint256" },
|
|
697
|
+
{ name: "amount", type: "uint256" },
|
|
698
|
+
{ name: "nonce", type: "uint256" }
|
|
699
|
+
]
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
// src/sdk/signatures/sign-lock.ts
|
|
703
|
+
async function signLockMessage({
|
|
704
|
+
walletClient,
|
|
705
|
+
chainId,
|
|
706
|
+
verifyingContract,
|
|
707
|
+
message
|
|
708
|
+
}) {
|
|
709
|
+
const account = walletClient.account;
|
|
710
|
+
if (!account) {
|
|
711
|
+
throw new Error("No account connected to wallet client");
|
|
712
|
+
}
|
|
713
|
+
const domain = createDomain(chainId, verifyingContract);
|
|
714
|
+
const signature = await walletClient.signTypedData({
|
|
715
|
+
account,
|
|
716
|
+
domain,
|
|
717
|
+
types: LOCK_TYPES,
|
|
718
|
+
primaryType: "Lock",
|
|
719
|
+
message
|
|
720
|
+
});
|
|
721
|
+
return signature;
|
|
722
|
+
}
|
|
723
|
+
function createLockExpiry(minutesFromNow = 60) {
|
|
724
|
+
return BigInt(Math.floor(Date.now() / 1e3) + minutesFromNow * 60);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// src/sdk/signatures/sign-modify-lock.ts
|
|
728
|
+
async function signModifyLockMessage({
|
|
729
|
+
walletClient,
|
|
730
|
+
chainId,
|
|
731
|
+
verifyingContract,
|
|
732
|
+
message
|
|
733
|
+
}) {
|
|
734
|
+
const account = walletClient.account;
|
|
735
|
+
if (!account) {
|
|
736
|
+
throw new Error("No account connected to wallet client");
|
|
737
|
+
}
|
|
738
|
+
const domain = createDomain(chainId, verifyingContract);
|
|
739
|
+
const signature = await walletClient.signTypedData({
|
|
740
|
+
account,
|
|
741
|
+
domain,
|
|
742
|
+
types: MODIFY_LOCK_TYPES,
|
|
743
|
+
primaryType: "ModifyLock",
|
|
744
|
+
message
|
|
745
|
+
});
|
|
746
|
+
return signature;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// src/sdk/signatures/sign-transfer.ts
|
|
750
|
+
async function signTransferMessage({
|
|
751
|
+
walletClient,
|
|
752
|
+
chainId,
|
|
753
|
+
verifyingContract,
|
|
754
|
+
message
|
|
755
|
+
}) {
|
|
756
|
+
const account = walletClient.account;
|
|
757
|
+
if (!account) {
|
|
758
|
+
throw new Error("No account connected to wallet client");
|
|
759
|
+
}
|
|
760
|
+
const domain = createDomain(chainId, verifyingContract);
|
|
761
|
+
const signature = await walletClient.signTypedData({
|
|
762
|
+
account,
|
|
763
|
+
domain,
|
|
764
|
+
types: TRANSFER_TYPES,
|
|
765
|
+
primaryType: "Transfer",
|
|
766
|
+
message
|
|
767
|
+
});
|
|
768
|
+
return signature;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// src/sdk/signatures/sign-transfer-locked.ts
|
|
772
|
+
async function signTransferLockedMessage({
|
|
773
|
+
walletClient,
|
|
774
|
+
chainId,
|
|
775
|
+
verifyingContract,
|
|
776
|
+
message
|
|
777
|
+
}) {
|
|
778
|
+
const account = walletClient.account;
|
|
779
|
+
if (!account) {
|
|
780
|
+
throw new Error("No account connected to wallet client");
|
|
781
|
+
}
|
|
782
|
+
const domain = createDomain(chainId, verifyingContract);
|
|
783
|
+
const signature = await walletClient.signTypedData({
|
|
784
|
+
account,
|
|
785
|
+
domain,
|
|
786
|
+
types: TRANSFER_LOCKED_TYPES,
|
|
787
|
+
primaryType: "TransferLocked",
|
|
788
|
+
message
|
|
789
|
+
});
|
|
790
|
+
return signature;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// src/sdk/signatures/sign-withdraw.ts
|
|
794
|
+
async function signWithdrawMessage({
|
|
795
|
+
walletClient,
|
|
796
|
+
chainId,
|
|
797
|
+
verifyingContract,
|
|
798
|
+
message
|
|
799
|
+
}) {
|
|
800
|
+
const account = walletClient.account;
|
|
801
|
+
if (!account) {
|
|
802
|
+
throw new Error("No account connected to wallet client");
|
|
803
|
+
}
|
|
804
|
+
const domain = createDomain(chainId, verifyingContract);
|
|
805
|
+
const signature = await walletClient.signTypedData({
|
|
806
|
+
account,
|
|
807
|
+
domain,
|
|
808
|
+
types: WITHDRAW_TYPES,
|
|
809
|
+
primaryType: "Withdraw",
|
|
810
|
+
message
|
|
811
|
+
});
|
|
812
|
+
return signature;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// src/sdk/signatures/sign-withdraw-from-lock.ts
|
|
816
|
+
async function signWithdrawFromLockMessage({
|
|
817
|
+
walletClient,
|
|
818
|
+
chainId,
|
|
819
|
+
verifyingContract,
|
|
820
|
+
message
|
|
821
|
+
}) {
|
|
822
|
+
const account = walletClient.account;
|
|
823
|
+
if (!account) {
|
|
824
|
+
throw new Error("No account connected to wallet client");
|
|
825
|
+
}
|
|
826
|
+
const domain = createDomain(chainId, verifyingContract);
|
|
827
|
+
const signature = await walletClient.signTypedData({
|
|
828
|
+
account,
|
|
829
|
+
domain,
|
|
830
|
+
types: WITHDRAW_FROM_LOCK_TYPES,
|
|
831
|
+
primaryType: "WithdrawFromLock",
|
|
832
|
+
message
|
|
833
|
+
});
|
|
834
|
+
return signature;
|
|
835
|
+
}
|
|
626
836
|
var defaultResult = {
|
|
627
837
|
address: void 0,
|
|
628
838
|
isConnected: false,
|
|
@@ -1168,6 +1378,205 @@ function usePrivanaContext() {
|
|
|
1168
1378
|
function useSafePrivanaContext() {
|
|
1169
1379
|
return useContext(PrivanaContext);
|
|
1170
1380
|
}
|
|
1381
|
+
|
|
1382
|
+
// src/sdk/hooks/browser-storage.ts
|
|
1383
|
+
function storageCandidate(name) {
|
|
1384
|
+
try {
|
|
1385
|
+
if (typeof window === "undefined") return void 0;
|
|
1386
|
+
return window[name] ?? void 0;
|
|
1387
|
+
} catch {
|
|
1388
|
+
return void 0;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
function storageCandidates() {
|
|
1392
|
+
return [storageCandidate("localStorage"), storageCandidate("sessionStorage")].filter(
|
|
1393
|
+
(storage) => storage !== void 0
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
function canUseBrowserStorage() {
|
|
1397
|
+
const probeKey = "privana:storage-probe";
|
|
1398
|
+
for (const storage of storageCandidates()) {
|
|
1399
|
+
try {
|
|
1400
|
+
storage.setItem(probeKey, "1");
|
|
1401
|
+
storage.removeItem(probeKey);
|
|
1402
|
+
return true;
|
|
1403
|
+
} catch {
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
return false;
|
|
1407
|
+
}
|
|
1408
|
+
function setBrowserStorageItem(key, value) {
|
|
1409
|
+
let stored = false;
|
|
1410
|
+
for (const storage of storageCandidates()) {
|
|
1411
|
+
try {
|
|
1412
|
+
storage.setItem(key, value);
|
|
1413
|
+
stored = true;
|
|
1414
|
+
} catch {
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
return stored;
|
|
1418
|
+
}
|
|
1419
|
+
function getBrowserStorageItem(key) {
|
|
1420
|
+
for (const storage of storageCandidates()) {
|
|
1421
|
+
try {
|
|
1422
|
+
const value = storage.getItem(key);
|
|
1423
|
+
if (value !== null) return value;
|
|
1424
|
+
} catch {
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
return null;
|
|
1428
|
+
}
|
|
1429
|
+
function removeBrowserStorageItem(key) {
|
|
1430
|
+
for (const storage of storageCandidates()) {
|
|
1431
|
+
try {
|
|
1432
|
+
storage.removeItem(key);
|
|
1433
|
+
} catch {
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
// src/sdk/hooks/pending-lock.ts
|
|
1439
|
+
var DEFAULT_LOCK_DURATION_SECONDS = 259200;
|
|
1440
|
+
var DEFAULT_ONRAMP_LOCK_BUFFER = 0.02;
|
|
1441
|
+
var BUFFER_SCALE = 1000000n;
|
|
1442
|
+
function applyLockBuffer(amount, buffer = DEFAULT_ONRAMP_LOCK_BUFFER) {
|
|
1443
|
+
if (!Number.isFinite(buffer) || buffer < 0 || buffer >= 1) {
|
|
1444
|
+
throw new Error(`Lock buffer must be in [0, 1), got ${buffer}`);
|
|
1445
|
+
}
|
|
1446
|
+
const shave = BigInt(Math.max(0, Math.ceil(buffer * Number(BUFFER_SCALE) - 1e-6)));
|
|
1447
|
+
return amount * (BUFFER_SCALE - shave) / BUFFER_SCALE;
|
|
1448
|
+
}
|
|
1449
|
+
function clampLockAmount(amount, maxAmount) {
|
|
1450
|
+
return maxAmount !== void 0 && maxAmount < amount ? maxAmount : amount;
|
|
1451
|
+
}
|
|
1452
|
+
async function createSignedLockRequest({
|
|
1453
|
+
client,
|
|
1454
|
+
walletClient,
|
|
1455
|
+
userAddress,
|
|
1456
|
+
networkConfig,
|
|
1457
|
+
serviceAddress,
|
|
1458
|
+
tokenId,
|
|
1459
|
+
amount,
|
|
1460
|
+
lockDuration = DEFAULT_LOCK_DURATION_SECONDS
|
|
1461
|
+
}) {
|
|
1462
|
+
if (amount <= 0n) {
|
|
1463
|
+
throw new Error("Lock amount must be positive");
|
|
1464
|
+
}
|
|
1465
|
+
const expiry = BigInt(Math.floor(Date.now() / 1e3) + lockDuration);
|
|
1466
|
+
const { nonce } = await client.getLockNonce(userAddress);
|
|
1467
|
+
const signature = await signLockMessage({
|
|
1468
|
+
walletClient,
|
|
1469
|
+
chainId: networkConfig.chainId,
|
|
1470
|
+
verifyingContract: networkConfig.accountingContract,
|
|
1471
|
+
message: {
|
|
1472
|
+
serviceAddress,
|
|
1473
|
+
tokenId,
|
|
1474
|
+
amount,
|
|
1475
|
+
expiry,
|
|
1476
|
+
nonce: BigInt(nonce)
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
return {
|
|
1480
|
+
service_address: serviceAddress,
|
|
1481
|
+
token_id: tokenId,
|
|
1482
|
+
amount: amount.toString(),
|
|
1483
|
+
expiry: expiry.toString(),
|
|
1484
|
+
nonce: String(nonce),
|
|
1485
|
+
signature
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
var EXPIRY_SLACK_SECONDS = 60;
|
|
1489
|
+
function isSignedLockUsable(payload) {
|
|
1490
|
+
const expiry = Number(payload.expiry);
|
|
1491
|
+
if (!Number.isFinite(expiry)) return false;
|
|
1492
|
+
return expiry > Math.floor(Date.now() / 1e3) + EXPIRY_SLACK_SECONDS;
|
|
1493
|
+
}
|
|
1494
|
+
var PostDepositLockError = class _PostDepositLockError extends Error {
|
|
1495
|
+
constructor(message, reason, signedAmount, creditedAmount, options) {
|
|
1496
|
+
super(message, options);
|
|
1497
|
+
this.reason = reason;
|
|
1498
|
+
this.signedAmount = signedAmount;
|
|
1499
|
+
this.creditedAmount = creditedAmount;
|
|
1500
|
+
this.name = "PostDepositLockError";
|
|
1501
|
+
Object.setPrototypeOf(this, _PostDepositLockError.prototype);
|
|
1502
|
+
}
|
|
1503
|
+
};
|
|
1504
|
+
async function submitPendingLock({
|
|
1505
|
+
client,
|
|
1506
|
+
payload,
|
|
1507
|
+
creditedAmount
|
|
1508
|
+
}) {
|
|
1509
|
+
let signedAmount;
|
|
1510
|
+
try {
|
|
1511
|
+
signedAmount = BigInt(payload.amount);
|
|
1512
|
+
} catch (err) {
|
|
1513
|
+
throw new PostDepositLockError(
|
|
1514
|
+
"Stored signed lock payload is malformed",
|
|
1515
|
+
"submission-failed",
|
|
1516
|
+
void 0,
|
|
1517
|
+
creditedAmount,
|
|
1518
|
+
{ cause: err }
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
if (!isSignedLockUsable(payload)) {
|
|
1522
|
+
throw new PostDepositLockError(
|
|
1523
|
+
"Signed lock expired before the deposit was credited",
|
|
1524
|
+
"expired",
|
|
1525
|
+
signedAmount,
|
|
1526
|
+
creditedAmount
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1529
|
+
if (creditedAmount !== void 0 && creditedAmount < signedAmount) {
|
|
1530
|
+
throw new PostDepositLockError(
|
|
1531
|
+
`Credited amount (${creditedAmount}) is below the signed lock amount (${signedAmount})`,
|
|
1532
|
+
"credited-below-signed",
|
|
1533
|
+
signedAmount,
|
|
1534
|
+
creditedAmount
|
|
1535
|
+
);
|
|
1536
|
+
}
|
|
1537
|
+
try {
|
|
1538
|
+
return await client.lockFunds(payload);
|
|
1539
|
+
} catch (err) {
|
|
1540
|
+
throw new PostDepositLockError(
|
|
1541
|
+
err instanceof Error ? err.message : "Lock submission failed",
|
|
1542
|
+
"submission-failed",
|
|
1543
|
+
signedAmount,
|
|
1544
|
+
creditedAmount,
|
|
1545
|
+
{ cause: err }
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
function pendingLockKey(userAddress, correlationId) {
|
|
1550
|
+
return `privana:pending-lock:${userAddress.toLowerCase()}:${correlationId}`;
|
|
1551
|
+
}
|
|
1552
|
+
function savePendingLock(userAddress, correlationId, payload) {
|
|
1553
|
+
const record = { payload, savedAt: Date.now() };
|
|
1554
|
+
const stored = setBrowserStorageItem(
|
|
1555
|
+
pendingLockKey(userAddress, correlationId),
|
|
1556
|
+
JSON.stringify(record)
|
|
1557
|
+
);
|
|
1558
|
+
if (!stored) {
|
|
1559
|
+
throw new Error("Unable to persist signed lock for recovery");
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
function loadPendingLock(userAddress, correlationId) {
|
|
1563
|
+
const key = pendingLockKey(userAddress, correlationId);
|
|
1564
|
+
try {
|
|
1565
|
+
const raw = getBrowserStorageItem(key);
|
|
1566
|
+
if (!raw) return void 0;
|
|
1567
|
+
const record = JSON.parse(raw);
|
|
1568
|
+
if (!record?.payload?.signature) {
|
|
1569
|
+
removeBrowserStorageItem(key);
|
|
1570
|
+
return void 0;
|
|
1571
|
+
}
|
|
1572
|
+
return record.payload;
|
|
1573
|
+
} catch {
|
|
1574
|
+
return void 0;
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
function clearPendingLock(userAddress, correlationId) {
|
|
1578
|
+
removeBrowserStorageItem(pendingLockKey(userAddress, correlationId));
|
|
1579
|
+
}
|
|
1171
1580
|
var INITIAL_AUTH_BACKOFF_MS = 5e3;
|
|
1172
1581
|
var MAX_AUTH_BACKOFF_MS = 6e4;
|
|
1173
1582
|
var DEFAULT_SIWE_AUTH_VALIDITY_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -1399,7 +1808,7 @@ function useDepositVerification(options = {}) {
|
|
|
1399
1808
|
const runVerification = useCallback(
|
|
1400
1809
|
async (ctx, generation) => {
|
|
1401
1810
|
const isStale = () => generation !== generationRef.current;
|
|
1402
|
-
const { hash, chainId, amount } = ctx;
|
|
1811
|
+
const { hash, chainId, amount, logIndex } = ctx;
|
|
1403
1812
|
setVerificationFailed(false);
|
|
1404
1813
|
setError(null);
|
|
1405
1814
|
setDidTimeout(false);
|
|
@@ -1427,7 +1836,8 @@ function useDepositVerification(options = {}) {
|
|
|
1427
1836
|
() => client.checkDeposit({
|
|
1428
1837
|
chain_id: chainId,
|
|
1429
1838
|
tx_hash: hash,
|
|
1430
|
-
amount: amount.toString()
|
|
1839
|
+
amount: amount.toString(),
|
|
1840
|
+
log_index: logIndex
|
|
1431
1841
|
})
|
|
1432
1842
|
);
|
|
1433
1843
|
if (result.status === "error" && isInsufficientFinalityMessage(result.detail)) {
|
|
@@ -1632,6 +2042,12 @@ function formatTimeRemaining(expiryTimestamp) {
|
|
|
1632
2042
|
}
|
|
1633
2043
|
return `${minutes}m left`;
|
|
1634
2044
|
}
|
|
2045
|
+
function formatCountdown(secondsLeft) {
|
|
2046
|
+
const clamped = Math.max(0, secondsLeft);
|
|
2047
|
+
const minutes = Math.floor(clamped / 60);
|
|
2048
|
+
const seconds = clamped % 60;
|
|
2049
|
+
return `${minutes}m:${String(seconds).padStart(2, "0")}s`;
|
|
2050
|
+
}
|
|
1635
2051
|
var buttonVariants = cva(
|
|
1636
2052
|
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
1637
2053
|
{
|
|
@@ -1700,6 +2116,198 @@ function getAction(client, actionFn, name) {
|
|
|
1700
2116
|
return (params) => actionFn(client, params);
|
|
1701
2117
|
}
|
|
1702
2118
|
|
|
2119
|
+
// ../../node_modules/@wagmi/core/dist/esm/version.js
|
|
2120
|
+
var version = "3.3.1";
|
|
2121
|
+
|
|
2122
|
+
// ../../node_modules/@wagmi/core/dist/esm/utils/getVersion.js
|
|
2123
|
+
var getVersion = () => `@wagmi/core@${version}`;
|
|
2124
|
+
|
|
2125
|
+
// ../../node_modules/@wagmi/core/dist/esm/errors/base.js
|
|
2126
|
+
var __classPrivateFieldGet = function(receiver, state, kind, f) {
|
|
2127
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
2128
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
2129
|
+
};
|
|
2130
|
+
var _BaseError_instances;
|
|
2131
|
+
var _BaseError_walk;
|
|
2132
|
+
var BaseError = class _BaseError extends Error {
|
|
2133
|
+
get docsBaseUrl() {
|
|
2134
|
+
return "https://wagmi.sh/core";
|
|
2135
|
+
}
|
|
2136
|
+
get version() {
|
|
2137
|
+
return getVersion();
|
|
2138
|
+
}
|
|
2139
|
+
constructor(shortMessage, options = {}) {
|
|
2140
|
+
super();
|
|
2141
|
+
_BaseError_instances.add(this);
|
|
2142
|
+
Object.defineProperty(this, "details", {
|
|
2143
|
+
enumerable: true,
|
|
2144
|
+
configurable: true,
|
|
2145
|
+
writable: true,
|
|
2146
|
+
value: void 0
|
|
2147
|
+
});
|
|
2148
|
+
Object.defineProperty(this, "docsPath", {
|
|
2149
|
+
enumerable: true,
|
|
2150
|
+
configurable: true,
|
|
2151
|
+
writable: true,
|
|
2152
|
+
value: void 0
|
|
2153
|
+
});
|
|
2154
|
+
Object.defineProperty(this, "metaMessages", {
|
|
2155
|
+
enumerable: true,
|
|
2156
|
+
configurable: true,
|
|
2157
|
+
writable: true,
|
|
2158
|
+
value: void 0
|
|
2159
|
+
});
|
|
2160
|
+
Object.defineProperty(this, "shortMessage", {
|
|
2161
|
+
enumerable: true,
|
|
2162
|
+
configurable: true,
|
|
2163
|
+
writable: true,
|
|
2164
|
+
value: void 0
|
|
2165
|
+
});
|
|
2166
|
+
Object.defineProperty(this, "name", {
|
|
2167
|
+
enumerable: true,
|
|
2168
|
+
configurable: true,
|
|
2169
|
+
writable: true,
|
|
2170
|
+
value: "WagmiCoreError"
|
|
2171
|
+
});
|
|
2172
|
+
const details = options.cause instanceof _BaseError ? options.cause.details : options.cause?.message ? options.cause.message : options.details;
|
|
2173
|
+
const docsPath = options.cause instanceof _BaseError ? options.cause.docsPath || options.docsPath : options.docsPath;
|
|
2174
|
+
this.message = [
|
|
2175
|
+
shortMessage || "An error occurred.",
|
|
2176
|
+
"",
|
|
2177
|
+
...options.metaMessages ? [...options.metaMessages, ""] : [],
|
|
2178
|
+
...docsPath ? [
|
|
2179
|
+
`Docs: ${this.docsBaseUrl}${docsPath}.html${options.docsSlug ? `#${options.docsSlug}` : ""}`
|
|
2180
|
+
] : [],
|
|
2181
|
+
...details ? [`Details: ${details}`] : [],
|
|
2182
|
+
`Version: ${this.version}`
|
|
2183
|
+
].join("\n");
|
|
2184
|
+
if (options.cause)
|
|
2185
|
+
this.cause = options.cause;
|
|
2186
|
+
this.details = details;
|
|
2187
|
+
this.docsPath = docsPath;
|
|
2188
|
+
this.metaMessages = options.metaMessages;
|
|
2189
|
+
this.shortMessage = shortMessage;
|
|
2190
|
+
}
|
|
2191
|
+
walk(fn) {
|
|
2192
|
+
return __classPrivateFieldGet(this, _BaseError_instances, "m", _BaseError_walk).call(this, this, fn);
|
|
2193
|
+
}
|
|
2194
|
+
};
|
|
2195
|
+
_BaseError_instances = /* @__PURE__ */ new WeakSet(), _BaseError_walk = function _BaseError_walk2(err, fn) {
|
|
2196
|
+
if (fn?.(err))
|
|
2197
|
+
return err;
|
|
2198
|
+
if (err.cause)
|
|
2199
|
+
return __classPrivateFieldGet(this, _BaseError_instances, "m", _BaseError_walk2).call(this, err.cause, fn);
|
|
2200
|
+
return err;
|
|
2201
|
+
};
|
|
2202
|
+
|
|
2203
|
+
// ../../node_modules/@wagmi/core/dist/esm/errors/config.js
|
|
2204
|
+
var ConnectorNotConnectedError = class extends BaseError {
|
|
2205
|
+
constructor() {
|
|
2206
|
+
super("Connector not connected.");
|
|
2207
|
+
Object.defineProperty(this, "name", {
|
|
2208
|
+
enumerable: true,
|
|
2209
|
+
configurable: true,
|
|
2210
|
+
writable: true,
|
|
2211
|
+
value: "ConnectorNotConnectedError"
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
};
|
|
2215
|
+
var ConnectorAccountNotFoundError = class extends BaseError {
|
|
2216
|
+
constructor({ address, connector }) {
|
|
2217
|
+
super(`Account "${address}" not found for connector "${connector.name}".`);
|
|
2218
|
+
Object.defineProperty(this, "name", {
|
|
2219
|
+
enumerable: true,
|
|
2220
|
+
configurable: true,
|
|
2221
|
+
writable: true,
|
|
2222
|
+
value: "ConnectorAccountNotFoundError"
|
|
2223
|
+
});
|
|
2224
|
+
}
|
|
2225
|
+
};
|
|
2226
|
+
var ConnectorChainMismatchError = class extends BaseError {
|
|
2227
|
+
constructor({ connectionChainId, connectorChainId }) {
|
|
2228
|
+
super(`The current chain of the connector (id: ${connectorChainId}) does not match the connection's chain (id: ${connectionChainId}).`, {
|
|
2229
|
+
metaMessages: [
|
|
2230
|
+
`Current Chain ID: ${connectorChainId}`,
|
|
2231
|
+
`Expected Chain ID: ${connectionChainId}`
|
|
2232
|
+
]
|
|
2233
|
+
});
|
|
2234
|
+
Object.defineProperty(this, "name", {
|
|
2235
|
+
enumerable: true,
|
|
2236
|
+
configurable: true,
|
|
2237
|
+
writable: true,
|
|
2238
|
+
value: "ConnectorChainMismatchError"
|
|
2239
|
+
});
|
|
2240
|
+
}
|
|
2241
|
+
};
|
|
2242
|
+
var ConnectorUnavailableReconnectingError = class extends BaseError {
|
|
2243
|
+
constructor({ connector }) {
|
|
2244
|
+
super(`Connector "${connector.name}" unavailable while reconnecting.`, {
|
|
2245
|
+
details: [
|
|
2246
|
+
"During the reconnection step, the only connector methods guaranteed to be available are: `id`, `name`, `type`, `uid`.",
|
|
2247
|
+
"All other methods are not guaranteed to be available until reconnection completes and connectors are fully restored.",
|
|
2248
|
+
"This error commonly occurs for connectors that asynchronously inject after reconnection has already started."
|
|
2249
|
+
].join(" ")
|
|
2250
|
+
});
|
|
2251
|
+
Object.defineProperty(this, "name", {
|
|
2252
|
+
enumerable: true,
|
|
2253
|
+
configurable: true,
|
|
2254
|
+
writable: true,
|
|
2255
|
+
value: "ConnectorUnavailableReconnectingError"
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
2258
|
+
};
|
|
2259
|
+
async function getConnectorClient(config, parameters = {}) {
|
|
2260
|
+
const { assertChainId = true } = parameters;
|
|
2261
|
+
let connection;
|
|
2262
|
+
if (parameters.connector) {
|
|
2263
|
+
const { connector: connector2 } = parameters;
|
|
2264
|
+
if (config.state.status === "reconnecting" && !connector2.getAccounts && !connector2.getChainId)
|
|
2265
|
+
throw new ConnectorUnavailableReconnectingError({ connector: connector2 });
|
|
2266
|
+
const [accounts, chainId2] = await Promise.all([
|
|
2267
|
+
connector2.getAccounts().catch((e) => {
|
|
2268
|
+
if (parameters.account === null)
|
|
2269
|
+
return [];
|
|
2270
|
+
throw e;
|
|
2271
|
+
}),
|
|
2272
|
+
connector2.getChainId()
|
|
2273
|
+
]);
|
|
2274
|
+
connection = {
|
|
2275
|
+
accounts,
|
|
2276
|
+
chainId: chainId2,
|
|
2277
|
+
connector: connector2
|
|
2278
|
+
};
|
|
2279
|
+
} else
|
|
2280
|
+
connection = config.state.connections.get(config.state.current);
|
|
2281
|
+
if (!connection)
|
|
2282
|
+
throw new ConnectorNotConnectedError();
|
|
2283
|
+
const chainId = parameters.chainId ?? connection.chainId;
|
|
2284
|
+
const connectorChainId = await connection.connector.getChainId();
|
|
2285
|
+
if (assertChainId && connectorChainId !== chainId)
|
|
2286
|
+
throw new ConnectorChainMismatchError({
|
|
2287
|
+
connectionChainId: chainId,
|
|
2288
|
+
connectorChainId
|
|
2289
|
+
});
|
|
2290
|
+
const connector = connection.connector;
|
|
2291
|
+
if (connector.getClient)
|
|
2292
|
+
return connector.getClient({ chainId });
|
|
2293
|
+
const account = parseAccount(parameters.account ?? connection.accounts[0]);
|
|
2294
|
+
if (account)
|
|
2295
|
+
account.address = getAddress(account.address);
|
|
2296
|
+
if (parameters.account && !connection.accounts.some((x) => x.toLowerCase() === account.address.toLowerCase()))
|
|
2297
|
+
throw new ConnectorAccountNotFoundError({
|
|
2298
|
+
address: account.address,
|
|
2299
|
+
connector
|
|
2300
|
+
});
|
|
2301
|
+
const chain = config.chains.find((chain2) => chain2.id === chainId);
|
|
2302
|
+
const provider = await connection.connector.getProvider({ chainId });
|
|
2303
|
+
return createClient({
|
|
2304
|
+
account,
|
|
2305
|
+
chain,
|
|
2306
|
+
name: "Connector Client",
|
|
2307
|
+
transport: (opts) => custom(provider)({ ...opts, retryCount: 0 })
|
|
2308
|
+
});
|
|
2309
|
+
}
|
|
2310
|
+
|
|
1703
2311
|
// ../../node_modules/@wagmi/core/dist/esm/actions/getChainId.js
|
|
1704
2312
|
function getChainId2(config) {
|
|
1705
2313
|
return config.state.chainId;
|
|
@@ -1710,6 +2318,10 @@ async function getTransactionReceipt(config, parameters) {
|
|
|
1710
2318
|
const action = getAction(client, getTransactionReceipt$1, "getTransactionReceipt");
|
|
1711
2319
|
return action(rest);
|
|
1712
2320
|
}
|
|
2321
|
+
async function getWalletClient3(config, parameters = {}) {
|
|
2322
|
+
const client = await getConnectorClient(config, parameters);
|
|
2323
|
+
return client.extend(walletActions);
|
|
2324
|
+
}
|
|
1713
2325
|
async function waitForTransactionReceipt(config, parameters) {
|
|
1714
2326
|
const { chainId, timeout = 0, ...rest } = parameters;
|
|
1715
2327
|
const client = config.getClient({ chainId });
|
|
@@ -1737,6 +2349,59 @@ async function waitForTransactionReceipt(config, parameters) {
|
|
|
1737
2349
|
chainId: client.chain.id
|
|
1738
2350
|
};
|
|
1739
2351
|
}
|
|
2352
|
+
function useEnsureCorrectChain() {
|
|
2353
|
+
const config = useConfig();
|
|
2354
|
+
const chainId = useChainId();
|
|
2355
|
+
const { switchChainAsync } = useSwitchChain();
|
|
2356
|
+
const waitUntilOnChain = useCallback(
|
|
2357
|
+
async (expectedChainId, timeoutMs, pollIntervalMs = 250) => {
|
|
2358
|
+
const startedAt = Date.now();
|
|
2359
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
2360
|
+
const currentChainId = getChainId2(config);
|
|
2361
|
+
if (currentChainId === expectedChainId) return true;
|
|
2362
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2363
|
+
}
|
|
2364
|
+
return false;
|
|
2365
|
+
},
|
|
2366
|
+
[config]
|
|
2367
|
+
);
|
|
2368
|
+
const ensureCorrectChain = useCallback(
|
|
2369
|
+
async (targetChainId) => {
|
|
2370
|
+
const currentChainId = getChainId2(config);
|
|
2371
|
+
if (currentChainId === targetChainId) return false;
|
|
2372
|
+
let switchErrorMessage;
|
|
2373
|
+
try {
|
|
2374
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
2375
|
+
setTimeout(() => reject(new Error("Chain switch timeout")), 3e3);
|
|
2376
|
+
});
|
|
2377
|
+
await Promise.race([switchChainAsync({ chainId: targetChainId }), timeoutPromise]);
|
|
2378
|
+
} catch (error) {
|
|
2379
|
+
if (error instanceof Error && error.message.includes("Unsupported Chain")) {
|
|
2380
|
+
console.warn("Got 'Unsupported Chain' error, chain may have switched anyway.");
|
|
2381
|
+
} else {
|
|
2382
|
+
switchErrorMessage = error instanceof Error ? error.message : "Unknown chain switch error";
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
const settled = await waitUntilOnChain(targetChainId, 2e4);
|
|
2386
|
+
if (settled) return true;
|
|
2387
|
+
if (switchErrorMessage) {
|
|
2388
|
+
throw new Error(
|
|
2389
|
+
`Failed to switch to chain (Chain ID: ${targetChainId}): ${switchErrorMessage}`
|
|
2390
|
+
);
|
|
2391
|
+
}
|
|
2392
|
+
throw new Error(`Chain switch did not settle in time (expected ${targetChainId}).`);
|
|
2393
|
+
},
|
|
2394
|
+
[config, switchChainAsync, waitUntilOnChain]
|
|
2395
|
+
);
|
|
2396
|
+
const isOnChain = useCallback((targetChainId) => chainId === targetChainId, [chainId]);
|
|
2397
|
+
return {
|
|
2398
|
+
chainId,
|
|
2399
|
+
ensureCorrectChain,
|
|
2400
|
+
isOnChain
|
|
2401
|
+
};
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
// src/sdk/hooks/use-fiat-on-ramp.ts
|
|
1740
2405
|
var DEFAULT_DELIVERY_TIMEOUT_MS = 12e4;
|
|
1741
2406
|
var DEFAULT_VERIFICATION_TIMEOUT_MS = 10 * 6e4;
|
|
1742
2407
|
var DEFAULT_FINALITY_RETRY_INTERVAL_MS = 15e3;
|
|
@@ -1744,14 +2409,26 @@ var ERC20_TRANSFER_EVENT = parseAbiItem(
|
|
|
1744
2409
|
"event Transfer(address indexed from, address indexed to, uint256 value)"
|
|
1745
2410
|
);
|
|
1746
2411
|
function useFiatOnRamp(options) {
|
|
1747
|
-
const {
|
|
2412
|
+
const {
|
|
2413
|
+
tokenId,
|
|
2414
|
+
postDepositLock,
|
|
2415
|
+
onCredited,
|
|
2416
|
+
onLockSubmitted,
|
|
2417
|
+
onLockFailed,
|
|
2418
|
+
onError,
|
|
2419
|
+
onDebugEvent
|
|
2420
|
+
} = options;
|
|
1748
2421
|
const deliveryTimeout = options.deliveryTimeout ?? DEFAULT_DELIVERY_TIMEOUT_MS;
|
|
1749
2422
|
const deliveryPollInterval = options.deliveryPollInterval ?? 3e3;
|
|
1750
2423
|
const verificationTimeout = options.verificationTimeout ?? DEFAULT_VERIFICATION_TIMEOUT_MS;
|
|
1751
2424
|
const finalityRetryInterval = options.finalityRetryInterval ?? DEFAULT_FINALITY_RETRY_INTERVAL_MS;
|
|
1752
|
-
const {
|
|
2425
|
+
const { address } = useAccount();
|
|
2426
|
+
const { data: walletClient } = useWalletClient();
|
|
2427
|
+
const { client, enabledTokens, networkConfig, serviceAddress } = usePrivanaContext();
|
|
1753
2428
|
const { executePrivateRead, privateReadReady } = usePrivateReadRequest();
|
|
2429
|
+
const { ensureCorrectChain } = useEnsureCorrectChain();
|
|
1754
2430
|
const wagmiConfig = useConfig();
|
|
2431
|
+
const queryClient = useQueryClient();
|
|
1755
2432
|
const selectedToken = enabledTokens.find((t) => t.id.toLowerCase() === tokenId.toLowerCase());
|
|
1756
2433
|
const [status, setStatus] = useState("idle");
|
|
1757
2434
|
const [pending, setPending] = useState([]);
|
|
@@ -1762,20 +2439,27 @@ function useFiatOnRamp(options) {
|
|
|
1762
2439
|
const [activeVerificationId, setActiveVerificationId] = useState(null);
|
|
1763
2440
|
const [finalityProgress, setFinalityProgress] = useState({});
|
|
1764
2441
|
const onCreditedRef = useRef(onCredited);
|
|
2442
|
+
const onLockSubmittedRef = useRef(onLockSubmitted);
|
|
2443
|
+
const onLockFailedRef = useRef(onLockFailed);
|
|
1765
2444
|
const onErrorRef = useRef(onError);
|
|
1766
2445
|
const onDebugEventRef = useRef(onDebugEvent);
|
|
1767
2446
|
const statusRef = useRef(status);
|
|
1768
2447
|
const activeIntentIdRef = useRef(null);
|
|
1769
2448
|
const activeVerificationRecordRef = useRef(null);
|
|
1770
2449
|
const activeVerificationKeyRef = useRef(null);
|
|
2450
|
+
const activeVerificationAmountRef = useRef(null);
|
|
2451
|
+
const lockOwnerRef = useRef(null);
|
|
1771
2452
|
const triggeredVerificationKeysRef = useRef(/* @__PURE__ */ new Set());
|
|
2453
|
+
const activeVerificationDoneRef = useRef(null);
|
|
1772
2454
|
const closeReconcilePromiseRef = useRef(null);
|
|
1773
2455
|
const purchaseInitiatedRef = useRef(false);
|
|
1774
2456
|
useEffect(() => {
|
|
1775
2457
|
onCreditedRef.current = onCredited;
|
|
2458
|
+
onLockSubmittedRef.current = onLockSubmitted;
|
|
2459
|
+
onLockFailedRef.current = onLockFailed;
|
|
1776
2460
|
onErrorRef.current = onError;
|
|
1777
2461
|
onDebugEventRef.current = onDebugEvent;
|
|
1778
|
-
}, [onCredited, onError, onDebugEvent]);
|
|
2462
|
+
}, [onCredited, onLockSubmitted, onLockFailed, onError, onDebugEvent]);
|
|
1779
2463
|
useEffect(() => {
|
|
1780
2464
|
statusRef.current = status;
|
|
1781
2465
|
}, [status]);
|
|
@@ -1856,13 +2540,64 @@ function useFiatOnRamp(options) {
|
|
|
1856
2540
|
useEffect(() => {
|
|
1857
2541
|
refreshPending();
|
|
1858
2542
|
}, [refreshPending]);
|
|
1859
|
-
const clearActiveVerification = useCallback(() => {
|
|
2543
|
+
const clearActiveVerification = useCallback((expectedKey) => {
|
|
1860
2544
|
const key = activeVerificationKeyRef.current;
|
|
2545
|
+
if (expectedKey != null && key !== null && key !== expectedKey) return;
|
|
1861
2546
|
if (key) triggeredVerificationKeysRef.current.delete(key);
|
|
1862
2547
|
activeVerificationKeyRef.current = null;
|
|
1863
2548
|
activeVerificationRecordRef.current = null;
|
|
2549
|
+
activeVerificationAmountRef.current = null;
|
|
1864
2550
|
setActiveVerificationId(null);
|
|
2551
|
+
activeVerificationDoneRef.current?.();
|
|
2552
|
+
activeVerificationDoneRef.current = null;
|
|
1865
2553
|
}, []);
|
|
2554
|
+
const submitPendingLockAfterCredit = useCallback(
|
|
2555
|
+
async (transactionId, userAddress) => {
|
|
2556
|
+
const signedLock = loadPendingLock(userAddress, transactionId);
|
|
2557
|
+
if (!signedLock) {
|
|
2558
|
+
clearPendingLock(userAddress, transactionId);
|
|
2559
|
+
if (!postDepositLock || transactionId !== activeIntentIdRef.current) return;
|
|
2560
|
+
const error2 = new PostDepositLockError(
|
|
2561
|
+
"No persisted signed lock found for this on-ramp",
|
|
2562
|
+
"not-found"
|
|
2563
|
+
);
|
|
2564
|
+
emitDebug("lock:not-found", { transactionId });
|
|
2565
|
+
(onLockFailedRef.current ?? onErrorRef.current)?.(error2);
|
|
2566
|
+
return;
|
|
2567
|
+
}
|
|
2568
|
+
const creditedAmount = activeVerificationAmountRef.current ?? void 0;
|
|
2569
|
+
try {
|
|
2570
|
+
const result = await submitPendingLock({ client, payload: signedLock, creditedAmount });
|
|
2571
|
+
queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
|
|
2572
|
+
queryClient.invalidateQueries({ queryKey: ["accounting-locked-funds"] });
|
|
2573
|
+
queryClient.invalidateQueries({ queryKey: ["accounting-total-locked-balance"] });
|
|
2574
|
+
queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
|
|
2575
|
+
emitDebug("lock:submitted", {
|
|
2576
|
+
transactionId,
|
|
2577
|
+
amount: signedLock.amount,
|
|
2578
|
+
submissionId: result.submission_id
|
|
2579
|
+
});
|
|
2580
|
+
onLockSubmittedRef.current?.(result);
|
|
2581
|
+
} catch (err) {
|
|
2582
|
+
const error2 = err instanceof PostDepositLockError ? err : new PostDepositLockError(
|
|
2583
|
+
err instanceof Error ? err.message : "Lock submission failed",
|
|
2584
|
+
"submission-failed",
|
|
2585
|
+
BigInt(signedLock.amount),
|
|
2586
|
+
creditedAmount,
|
|
2587
|
+
{ cause: err }
|
|
2588
|
+
);
|
|
2589
|
+
emitDebug("lock:failed", {
|
|
2590
|
+
transactionId,
|
|
2591
|
+
reason: error2.reason,
|
|
2592
|
+
message: error2.message
|
|
2593
|
+
});
|
|
2594
|
+
(onLockFailedRef.current ?? onErrorRef.current)?.(error2);
|
|
2595
|
+
} finally {
|
|
2596
|
+
clearPendingLock(userAddress, transactionId);
|
|
2597
|
+
}
|
|
2598
|
+
},
|
|
2599
|
+
[client, emitDebug, postDepositLock, queryClient]
|
|
2600
|
+
);
|
|
1866
2601
|
const { verify } = useDepositVerification({
|
|
1867
2602
|
pollTimeout: verificationTimeout,
|
|
1868
2603
|
pollInterval: options.verificationPollInterval,
|
|
@@ -1878,6 +2613,7 @@ function useFiatOnRamp(options) {
|
|
|
1878
2613
|
},
|
|
1879
2614
|
onCredited: (depositTxHash) => {
|
|
1880
2615
|
const record = activeVerificationRecordRef.current;
|
|
2616
|
+
const verificationKey = record ? getOnRampVerificationKey(record) : null;
|
|
1881
2617
|
emitDebug("verification:credited", {
|
|
1882
2618
|
depositTxHash,
|
|
1883
2619
|
record: record ? summariseOnRampRecord(record) : null
|
|
@@ -1892,6 +2628,18 @@ function useFiatOnRamp(options) {
|
|
|
1892
2628
|
delete next[record.transaction_id];
|
|
1893
2629
|
return next;
|
|
1894
2630
|
});
|
|
2631
|
+
const lockOwner = lockOwnerRef.current ?? address;
|
|
2632
|
+
if (lockOwner) {
|
|
2633
|
+
void submitPendingLockAfterCredit(record.transaction_id, lockOwner);
|
|
2634
|
+
} else if (postDepositLock) {
|
|
2635
|
+
emitDebug("lock:owner-unavailable", { transactionId: record.transaction_id });
|
|
2636
|
+
(onLockFailedRef.current ?? onErrorRef.current)?.(
|
|
2637
|
+
new PostDepositLockError(
|
|
2638
|
+
"No wallet address available to look up the signed lock for this on-ramp",
|
|
2639
|
+
"not-found"
|
|
2640
|
+
)
|
|
2641
|
+
);
|
|
2642
|
+
}
|
|
1895
2643
|
}
|
|
1896
2644
|
void (async () => {
|
|
1897
2645
|
try {
|
|
@@ -1914,7 +2662,7 @@ function useFiatOnRamp(options) {
|
|
|
1914
2662
|
console.warn("Failed to mark on-ramp row complete:", err);
|
|
1915
2663
|
} finally {
|
|
1916
2664
|
await refreshPending();
|
|
1917
|
-
clearActiveVerification();
|
|
2665
|
+
clearActiveVerification(verificationKey);
|
|
1918
2666
|
if (record && activeIntentIdRef.current === record.transaction_id) {
|
|
1919
2667
|
activeIntentIdRef.current = null;
|
|
1920
2668
|
setActiveIntentId(null);
|
|
@@ -1952,7 +2700,8 @@ function useFiatOnRamp(options) {
|
|
|
1952
2700
|
async ({
|
|
1953
2701
|
currencyCode,
|
|
1954
2702
|
baseCurrencyCode,
|
|
1955
|
-
baseCurrencyAmount
|
|
2703
|
+
baseCurrencyAmount,
|
|
2704
|
+
quoteCurrencyAmount
|
|
1956
2705
|
}) => {
|
|
1957
2706
|
try {
|
|
1958
2707
|
setError(null);
|
|
@@ -1960,12 +2709,34 @@ function useFiatOnRamp(options) {
|
|
|
1960
2709
|
const token = enabledTokens.find((t) => t.id.toLowerCase() === tokenId.toLowerCase());
|
|
1961
2710
|
if (!token) throw new Error(`Unknown token: ${tokenId}`);
|
|
1962
2711
|
if (!depositAddress) throw new Error("Privana deposit address is not ready");
|
|
2712
|
+
let lockAmount;
|
|
2713
|
+
if (postDepositLock) {
|
|
2714
|
+
if (!address || !walletClient) throw new Error("Wallet not connected");
|
|
2715
|
+
if (!quoteCurrencyAmount) {
|
|
2716
|
+
throw new Error(
|
|
2717
|
+
"postDepositLock requires quoteCurrencyAmount to derive the lock amount"
|
|
2718
|
+
);
|
|
2719
|
+
}
|
|
2720
|
+
if (!canUseBrowserStorage()) {
|
|
2721
|
+
throw new Error("Browser storage is required for locked on-ramp recovery");
|
|
2722
|
+
}
|
|
2723
|
+
const buffered = applyLockBuffer(
|
|
2724
|
+
parseUnits(quoteCurrencyAmount, token.decimals),
|
|
2725
|
+
postDepositLock.buffer
|
|
2726
|
+
);
|
|
2727
|
+
lockAmount = clampLockAmount(buffered, postDepositLock.maxAmount);
|
|
2728
|
+
if (lockAmount <= 0n) {
|
|
2729
|
+
throw new Error(`Post-deposit lock amount must be positive, got ${lockAmount}`);
|
|
2730
|
+
}
|
|
2731
|
+
await ensureCorrectChain(networkConfig.chainId);
|
|
2732
|
+
}
|
|
1963
2733
|
emitDebug("intent:create-request", {
|
|
1964
2734
|
tokenId,
|
|
1965
2735
|
chainId: token.chainId,
|
|
1966
2736
|
currencyCode,
|
|
1967
2737
|
baseCurrencyCode: baseCurrencyCode ?? null,
|
|
1968
2738
|
baseCurrencyAmount: baseCurrencyAmount ?? null,
|
|
2739
|
+
quoteCurrencyAmount: quoteCurrencyAmount ?? null,
|
|
1969
2740
|
depositAddress
|
|
1970
2741
|
});
|
|
1971
2742
|
const record = await executePrivateRead(
|
|
@@ -1978,6 +2749,28 @@ function useFiatOnRamp(options) {
|
|
|
1978
2749
|
base_currency_amount: baseCurrencyAmount
|
|
1979
2750
|
})
|
|
1980
2751
|
);
|
|
2752
|
+
if (postDepositLock && address && walletClient && lockAmount !== void 0) {
|
|
2753
|
+
const signingWalletClient = await getWalletClient3(wagmiConfig, {
|
|
2754
|
+
chainId: networkConfig.chainId
|
|
2755
|
+
});
|
|
2756
|
+
const signedLock = await createSignedLockRequest({
|
|
2757
|
+
client,
|
|
2758
|
+
walletClient: signingWalletClient,
|
|
2759
|
+
userAddress: address,
|
|
2760
|
+
networkConfig,
|
|
2761
|
+
serviceAddress: requireServiceAddress(postDepositLock.serviceAddress ?? serviceAddress),
|
|
2762
|
+
tokenId,
|
|
2763
|
+
amount: lockAmount,
|
|
2764
|
+
lockDuration: postDepositLock.lockDuration
|
|
2765
|
+
});
|
|
2766
|
+
savePendingLock(address, record.transaction_id, signedLock);
|
|
2767
|
+
lockOwnerRef.current = address;
|
|
2768
|
+
emitDebug("intent:lock-signed", {
|
|
2769
|
+
transactionId: record.transaction_id,
|
|
2770
|
+
amount: signedLock.amount,
|
|
2771
|
+
expiry: signedLock.expiry
|
|
2772
|
+
});
|
|
2773
|
+
}
|
|
1981
2774
|
activeIntentIdRef.current = record.transaction_id;
|
|
1982
2775
|
setActiveIntentId(record.transaction_id);
|
|
1983
2776
|
emitDebug("intent:create-success", {
|
|
@@ -1993,7 +2786,21 @@ function useFiatOnRamp(options) {
|
|
|
1993
2786
|
throw e;
|
|
1994
2787
|
}
|
|
1995
2788
|
},
|
|
1996
|
-
[
|
|
2789
|
+
[
|
|
2790
|
+
address,
|
|
2791
|
+
client,
|
|
2792
|
+
depositAddress,
|
|
2793
|
+
emitDebug,
|
|
2794
|
+
enabledTokens,
|
|
2795
|
+
ensureCorrectChain,
|
|
2796
|
+
executePrivateRead,
|
|
2797
|
+
networkConfig,
|
|
2798
|
+
postDepositLock,
|
|
2799
|
+
serviceAddress,
|
|
2800
|
+
tokenId,
|
|
2801
|
+
wagmiConfig,
|
|
2802
|
+
walletClient
|
|
2803
|
+
]
|
|
1997
2804
|
);
|
|
1998
2805
|
const registerOnRampTokenMapping = useCallback(
|
|
1999
2806
|
async (moonpayTransactionId) => {
|
|
@@ -2115,6 +2922,12 @@ function useFiatOnRamp(options) {
|
|
|
2115
2922
|
});
|
|
2116
2923
|
return;
|
|
2117
2924
|
}
|
|
2925
|
+
const supersededKey = activeVerificationKeyRef.current;
|
|
2926
|
+
if (supersededKey && supersededKey !== verificationKey) {
|
|
2927
|
+
triggeredVerificationKeysRef.current.delete(supersededKey);
|
|
2928
|
+
}
|
|
2929
|
+
activeVerificationDoneRef.current?.();
|
|
2930
|
+
activeVerificationDoneRef.current = null;
|
|
2118
2931
|
triggeredVerificationKeysRef.current.add(verificationKey);
|
|
2119
2932
|
activeVerificationKeyRef.current = verificationKey;
|
|
2120
2933
|
activeVerificationRecordRef.current = record;
|
|
@@ -2165,6 +2978,7 @@ function useFiatOnRamp(options) {
|
|
|
2165
2978
|
`Delivered amount (${record.quote_currency_amount}) is below the minimum deposit.`
|
|
2166
2979
|
);
|
|
2167
2980
|
}
|
|
2981
|
+
activeVerificationAmountRef.current = amount;
|
|
2168
2982
|
if (activeIntentIdRef.current === record.transaction_id) {
|
|
2169
2983
|
setStatus("verifying");
|
|
2170
2984
|
}
|
|
@@ -2183,6 +2997,7 @@ function useFiatOnRamp(options) {
|
|
|
2183
2997
|
if (activeVerificationKeyRef.current === verificationKey) {
|
|
2184
2998
|
activeVerificationKeyRef.current = null;
|
|
2185
2999
|
activeVerificationRecordRef.current = null;
|
|
3000
|
+
activeVerificationAmountRef.current = null;
|
|
2186
3001
|
setActiveVerificationId(null);
|
|
2187
3002
|
}
|
|
2188
3003
|
throw err;
|
|
@@ -2241,6 +3056,7 @@ function useFiatOnRamp(options) {
|
|
|
2241
3056
|
previousStatus,
|
|
2242
3057
|
transactionId
|
|
2243
3058
|
});
|
|
3059
|
+
if (address) clearPendingLock(address, transactionId);
|
|
2244
3060
|
await refreshPending();
|
|
2245
3061
|
if (previousStatus === "awaiting-purchase" || previousStatus === "awaiting-delivery") {
|
|
2246
3062
|
setStatus("idle");
|
|
@@ -2271,7 +3087,7 @@ function useFiatOnRamp(options) {
|
|
|
2271
3087
|
} finally {
|
|
2272
3088
|
closeReconcilePromiseRef.current = null;
|
|
2273
3089
|
}
|
|
2274
|
-
}, [emitDebug, refreshPending, triggerVerification, waitForOnChainHash]);
|
|
3090
|
+
}, [address, emitDebug, refreshPending, triggerVerification, waitForOnChainHash]);
|
|
2275
3091
|
const finishPendingVerification = useCallback(
|
|
2276
3092
|
async (record) => {
|
|
2277
3093
|
try {
|
|
@@ -2305,6 +3121,12 @@ function useFiatOnRamp(options) {
|
|
|
2305
3121
|
try {
|
|
2306
3122
|
await triggerVerificationRef.current(record);
|
|
2307
3123
|
} catch {
|
|
3124
|
+
continue;
|
|
3125
|
+
}
|
|
3126
|
+
if (activeVerificationKeyRef.current === key) {
|
|
3127
|
+
await new Promise((resolve) => {
|
|
3128
|
+
activeVerificationDoneRef.current = resolve;
|
|
3129
|
+
});
|
|
2308
3130
|
}
|
|
2309
3131
|
}
|
|
2310
3132
|
})();
|
|
@@ -2421,6 +3243,12 @@ function matchesOnRampTransaction(record, transactionId) {
|
|
|
2421
3243
|
function getOnRampVerificationKey(record) {
|
|
2422
3244
|
return record.on_chain_tx_hash ?? record.transaction_id;
|
|
2423
3245
|
}
|
|
3246
|
+
function requireServiceAddress(serviceAddress) {
|
|
3247
|
+
if (!serviceAddress) {
|
|
3248
|
+
throw new Error("Service address not configured");
|
|
3249
|
+
}
|
|
3250
|
+
return serviceAddress;
|
|
3251
|
+
}
|
|
2424
3252
|
function summariseMoonPayEventProps(props) {
|
|
2425
3253
|
return {
|
|
2426
3254
|
id: props.id,
|
|
@@ -2478,6 +3306,7 @@ function useMoonPayBuyWidget({
|
|
|
2478
3306
|
colorCode,
|
|
2479
3307
|
baseCurrencyCode,
|
|
2480
3308
|
baseCurrencyAmount,
|
|
3309
|
+
quoteCurrencyAmount,
|
|
2481
3310
|
lockAmount,
|
|
2482
3311
|
paymentMethod,
|
|
2483
3312
|
currencyCode,
|
|
@@ -2537,6 +3366,7 @@ function useMoonPayBuyWidget({
|
|
|
2537
3366
|
overlayNode,
|
|
2538
3367
|
baseCurrencyCode,
|
|
2539
3368
|
baseCurrencyAmount,
|
|
3369
|
+
quoteCurrencyAmount,
|
|
2540
3370
|
lockAmount: lockAmount ? "true" : void 0,
|
|
2541
3371
|
paymentMethod,
|
|
2542
3372
|
currencyCode,
|
|
@@ -2562,6 +3392,7 @@ function useMoonPayBuyWidget({
|
|
|
2562
3392
|
overlayNode,
|
|
2563
3393
|
baseCurrencyCode,
|
|
2564
3394
|
baseCurrencyAmount,
|
|
3395
|
+
quoteCurrencyAmount,
|
|
2565
3396
|
lockAmount,
|
|
2566
3397
|
paymentMethod,
|
|
2567
3398
|
currencyCode,
|
|
@@ -2580,6 +3411,7 @@ function FiatOnRampForm({
|
|
|
2580
3411
|
currencyCode,
|
|
2581
3412
|
baseCurrencyCode = "usd",
|
|
2582
3413
|
defaultBaseCurrencyAmount = "100",
|
|
3414
|
+
quoteCurrencyAmount,
|
|
2583
3415
|
tokenSymbol,
|
|
2584
3416
|
theme,
|
|
2585
3417
|
themeId,
|
|
@@ -2588,7 +3420,10 @@ function FiatOnRampForm({
|
|
|
2588
3420
|
autoStart = false,
|
|
2589
3421
|
lockAmount,
|
|
2590
3422
|
paymentMethod,
|
|
3423
|
+
postDepositLock,
|
|
2591
3424
|
onCredited,
|
|
3425
|
+
onLockSubmitted,
|
|
3426
|
+
onLockFailed,
|
|
2592
3427
|
onError,
|
|
2593
3428
|
onDebugEvent
|
|
2594
3429
|
}) {
|
|
@@ -2596,6 +3431,8 @@ function FiatOnRampForm({
|
|
|
2596
3431
|
const [visible, setVisible] = useState(false);
|
|
2597
3432
|
const [isPreparing, setIsPreparing] = useState(false);
|
|
2598
3433
|
const [rowError, setRowError] = useState(null);
|
|
3434
|
+
const [lockError, setLockError] = useState(null);
|
|
3435
|
+
const [lockSettled, setLockSettled] = useState(false);
|
|
2599
3436
|
const {
|
|
2600
3437
|
status,
|
|
2601
3438
|
activeIntentId,
|
|
@@ -2613,7 +3450,25 @@ function FiatOnRampForm({
|
|
|
2613
3450
|
finishPendingVerification,
|
|
2614
3451
|
handleWidgetClosed,
|
|
2615
3452
|
refreshPending
|
|
2616
|
-
} = useFiatOnRamp({
|
|
3453
|
+
} = useFiatOnRamp({
|
|
3454
|
+
tokenId,
|
|
3455
|
+
postDepositLock,
|
|
3456
|
+
onCredited,
|
|
3457
|
+
// Lock callbacks aren't intent-keyed, so a resumed background row's lock
|
|
3458
|
+
// can settle these flags while a newer purchase is still locking — a
|
|
3459
|
+
// transient overpromise that the newer lock's own outcome then corrects.
|
|
3460
|
+
onLockSubmitted: (response) => {
|
|
3461
|
+
setLockError(null);
|
|
3462
|
+
setLockSettled(true);
|
|
3463
|
+
onLockSubmitted?.(response);
|
|
3464
|
+
},
|
|
3465
|
+
onLockFailed: (err) => {
|
|
3466
|
+
setLockError(err.message);
|
|
3467
|
+
onLockFailed?.(err);
|
|
3468
|
+
},
|
|
3469
|
+
onError,
|
|
3470
|
+
onDebugEvent
|
|
3471
|
+
});
|
|
2617
3472
|
const decimals = selectedToken?.decimals;
|
|
2618
3473
|
const displaySymbol = tokenSymbol ?? selectedToken?.symbol ?? currencyCode.toUpperCase();
|
|
2619
3474
|
const emitFormDebug = useCallback(
|
|
@@ -2629,8 +3484,17 @@ function FiatOnRampForm({
|
|
|
2629
3484
|
[onDebugEvent, status, tokenId]
|
|
2630
3485
|
);
|
|
2631
3486
|
const minFiatGate = minDepositBaseUnits !== void 0 && decimals !== void 0 ? Number(formatUnits(minDepositBaseUnits, decimals)) * 1.05 : void 0;
|
|
2632
|
-
const
|
|
3487
|
+
const { units: quoteBaseUnits, failed: quoteParseFailed } = (() => {
|
|
3488
|
+
if (!quoteCurrencyAmount || decimals === void 0) return { units: void 0, failed: false };
|
|
3489
|
+
try {
|
|
3490
|
+
return { units: parseUnits(quoteCurrencyAmount, decimals), failed: false };
|
|
3491
|
+
} catch {
|
|
3492
|
+
return { units: void 0, failed: true };
|
|
3493
|
+
}
|
|
3494
|
+
})();
|
|
3495
|
+
const isBelowMin = quoteBaseUnits !== void 0 && minDepositBaseUnits !== void 0 ? quoteBaseUnits < minDepositBaseUnits : minFiatGate !== void 0 && Number(defaultBaseCurrencyAmount) < minFiatGate;
|
|
2633
3496
|
const isBusy = isPreparing || status === "awaiting-purchase";
|
|
3497
|
+
const lockPending = !!postDepositLock && status === "credited" && !lockSettled && !lockError;
|
|
2634
3498
|
const isInitializing = !!address && !depositAddress;
|
|
2635
3499
|
const isPrePurchase = status === "idle" || status === "awaiting-purchase";
|
|
2636
3500
|
const isVerifying = status === "awaiting-delivery" || status === "verifying";
|
|
@@ -2640,9 +3504,10 @@ function FiatOnRampForm({
|
|
|
2640
3504
|
!depositAddress ? "deposit-address-not-loaded" : null,
|
|
2641
3505
|
isBusy ? `busy:${isPreparing ? "preparing" : status}` : null,
|
|
2642
3506
|
visible ? "widget-open" : null,
|
|
2643
|
-
isBelowMin ? "below-minimum" : null
|
|
3507
|
+
isBelowMin ? "below-minimum" : null,
|
|
3508
|
+
quoteParseFailed ? "invalid-quote-amount" : null
|
|
2644
3509
|
].filter((reason) => Boolean(reason)),
|
|
2645
|
-
[address, depositAddress, isBelowMin, isBusy, isPreparing, status, visible]
|
|
3510
|
+
[address, depositAddress, isBelowMin, isBusy, isPreparing, quoteParseFailed, status, visible]
|
|
2646
3511
|
);
|
|
2647
3512
|
const canBuy = blockReasons.length === 0;
|
|
2648
3513
|
const handleOpen = useCallback(async () => {
|
|
@@ -2661,6 +3526,8 @@ function FiatOnRampForm({
|
|
|
2661
3526
|
return;
|
|
2662
3527
|
}
|
|
2663
3528
|
setIsPreparing(true);
|
|
3529
|
+
setLockError(null);
|
|
3530
|
+
setLockSettled(false);
|
|
2664
3531
|
emitFormDebug("form:open-click", {
|
|
2665
3532
|
currencyCode,
|
|
2666
3533
|
tokenSymbol: displaySymbol,
|
|
@@ -2674,7 +3541,8 @@ function FiatOnRampForm({
|
|
|
2674
3541
|
const intent = await prepareOnRampIntent({
|
|
2675
3542
|
currencyCode,
|
|
2676
3543
|
baseCurrencyCode,
|
|
2677
|
-
baseCurrencyAmount: defaultBaseCurrencyAmount
|
|
3544
|
+
baseCurrencyAmount: defaultBaseCurrencyAmount,
|
|
3545
|
+
quoteCurrencyAmount
|
|
2678
3546
|
});
|
|
2679
3547
|
emitFormDebug("form:intent-ready", {
|
|
2680
3548
|
transactionId: intent.transaction_id,
|
|
@@ -2699,6 +3567,7 @@ function FiatOnRampForm({
|
|
|
2699
3567
|
decimals,
|
|
2700
3568
|
displaySymbol,
|
|
2701
3569
|
defaultBaseCurrencyAmount,
|
|
3570
|
+
quoteCurrencyAmount,
|
|
2702
3571
|
depositAddress,
|
|
2703
3572
|
emitFormDebug,
|
|
2704
3573
|
prepareOnRampIntent,
|
|
@@ -2729,6 +3598,7 @@ function FiatOnRampForm({
|
|
|
2729
3598
|
colorCode,
|
|
2730
3599
|
baseCurrencyCode,
|
|
2731
3600
|
baseCurrencyAmount: defaultBaseCurrencyAmount,
|
|
3601
|
+
quoteCurrencyAmount,
|
|
2732
3602
|
lockAmount,
|
|
2733
3603
|
paymentMethod,
|
|
2734
3604
|
currencyCode,
|
|
@@ -2801,7 +3671,7 @@ function FiatOnRampForm({
|
|
|
2801
3671
|
);
|
|
2802
3672
|
})
|
|
2803
3673
|
] }),
|
|
2804
|
-
status === "credited" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 py-8 text-center", children: [
|
|
3674
|
+
status === "credited" && !lockPending && !lockError && /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 py-8 text-center", children: [
|
|
2805
3675
|
/* @__PURE__ */ jsx(CircleCheckIcon, { className: "text-primary size-8", "aria-hidden": true }),
|
|
2806
3676
|
/* @__PURE__ */ jsx("p", { className: "text-foreground text-sm font-medium", children: "Purchase credited" }),
|
|
2807
3677
|
/* @__PURE__ */ jsxs("p", { className: "text-muted-foreground text-sm", children: [
|
|
@@ -2810,12 +3680,20 @@ function FiatOnRampForm({
|
|
|
2810
3680
|
" deposit is now available in your balance."
|
|
2811
3681
|
] })
|
|
2812
3682
|
] }),
|
|
3683
|
+
lockPending && /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [
|
|
3684
|
+
/* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
3685
|
+
"Purchase credited \u2014 locking your funds\u2026"
|
|
3686
|
+
] }),
|
|
2813
3687
|
autoStart ? !visible && isPrePurchase && /* @__PURE__ */ jsx(Skeleton, { className: "h-[656px] w-full rounded-md" }) : isInitializing ? /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-full rounded-md" }) : /* @__PURE__ */ jsxs(Button, { type: "button", onClick: handleOpen, disabled: !canBuy, children: [
|
|
2814
3688
|
(isBusy || visible) && /* @__PURE__ */ jsx(Loader2, { className: "animate-spin", "aria-hidden": true }),
|
|
2815
3689
|
"Buy"
|
|
2816
3690
|
] }),
|
|
2817
3691
|
widgetElement,
|
|
2818
3692
|
error && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", role: "alert", children: error.message }),
|
|
3693
|
+
lockError && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", role: "alert", children: [
|
|
3694
|
+
"Purchase credited to your account, but locking the funds to a service failed: ",
|
|
3695
|
+
lockError
|
|
3696
|
+
] }),
|
|
2819
3697
|
isBelowMin && minFiatGate !== void 0 && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", role: "alert", children: [
|
|
2820
3698
|
"Minimum purchase is ~$",
|
|
2821
3699
|
minFiatGate.toFixed(2),
|
|
@@ -2833,6 +3711,6 @@ function parseFinalityProgress(message) {
|
|
|
2833
3711
|
return match ? `${match[1]} confirmations` : null;
|
|
2834
3712
|
}
|
|
2835
3713
|
|
|
2836
|
-
export { AccountingApiError, Button, FiatOnRampForm, HOSTED_AUTH_CLOCK_SKEW_MS, HostedAuthError, HostedAuthRequiredError, HostedAuthStateMismatchError, HttpClient, NETWORK_CONFIG, NetworkError, PrivanaClient, PrivanaProvider, SUPPORTED_CHAINS, SiweAuthProvider, Skeleton, ValidationError, applyRefreshResponse, buildHostedAuthSession, buildSiweStatement, buttonVariants, clearHostedAuthPendingTransaction, cn, createHostedAuthPendingStorageKey, createHostedAuthState, createHostedAuthStorageKey, createPkceChallenge, createPkceVerifier, formatTimeRemaining, formatTokenAmount, getAccountingContract, getApiUrl, getChainById, getChainId,
|
|
2837
|
-
//# sourceMappingURL=chunk-
|
|
2838
|
-
//# sourceMappingURL=chunk-
|
|
3714
|
+
export { AccountingApiError, Button, DEFAULT_LOCK_DURATION_SECONDS, DEFAULT_ONRAMP_LOCK_BUFFER, FiatOnRampForm, HOSTED_AUTH_CLOCK_SKEW_MS, HostedAuthError, HostedAuthRequiredError, HostedAuthStateMismatchError, HttpClient, LOCK_TYPES, MODIFY_LOCK_TYPES, NETWORK_CONFIG, NetworkError, PostDepositLockError, PrivanaClient, PrivanaProvider, SUPPORTED_CHAINS, SiweAuthProvider, Skeleton, TRANSFER_LOCKED_TYPES, TRANSFER_TYPES, ValidationError, WITHDRAW_FROM_LOCK_TYPES, WITHDRAW_TYPES, applyLockBuffer, applyRefreshResponse, buildHostedAuthSession, buildSiweStatement, buttonVariants, canUseBrowserStorage, clampLockAmount, clearHostedAuthPendingTransaction, clearPendingLock, cn, createDomain, createHostedAuthPendingStorageKey, createHostedAuthState, createHostedAuthStorageKey, createLockExpiry, createPkceChallenge, createPkceVerifier, createSignedLockRequest, formatCountdown, formatTimeRemaining, formatTokenAmount, getAccountingContract, getApiUrl, getBrowserStorageItem, getChainById, getChainId, getExplorerAddressUrl, getExplorerLabel, getTransactionReceipt, getWalletClient3 as getWalletClient, isHostedAuthRefreshActive, isHostedAuthSessionActive, isSignedLockUsable, loadPendingLock, normalizeAddress, normalizeHex, parseHostedAuthCallback, parseTokenAmount, persistHostedAuthPendingTransaction, readHostedAuthPendingTransaction, readStoredHostedAuthSession, removeBrowserStorageItem, savePendingLock, setBrowserStorageItem, shortenAddress, signLockMessage, signModifyLockMessage, signTransferLockedMessage, signTransferMessage, signWithdrawFromLockMessage, signWithdrawMessage, stripHostedAuthCallbackParams, submitPendingLock, syncHostedAuthSessionToClient, useDepositVerification, useEnsureCorrectChain, useFiatOnRamp, usePrivanaContext, usePrivateReadRequest, useSafeAccount, useSafePrivanaContext, useSiweAuth, waitForTransactionReceipt };
|
|
3715
|
+
//# sourceMappingURL=chunk-SAJ7K5WT.js.map
|
|
3716
|
+
//# sourceMappingURL=chunk-SAJ7K5WT.js.map
|