@coin-voyage/paykit 2.4.3-beta.0 → 2.4.4-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -17
- package/dist/components/Pages/CardPayment/index.js +5 -3
- package/dist/components/Pages/Confirmation/index.js +16 -6
- package/dist/components/Pages/PayToAddress/index.js +3 -3
- package/dist/components/Pages/PreparingPayment/index.d.ts +1 -0
- package/dist/components/Pages/PreparingPayment/index.js +50 -0
- package/dist/components/pay-button/index.js +173 -93
- package/dist/components/pay-modal/index.d.ts +3 -1
- package/dist/components/pay-modal/index.js +2 -2
- package/dist/components/ui/Modal/index.d.ts +2 -1
- package/dist/components/ui/Modal/index.js +8 -1
- package/dist/config/route-config.js +7 -0
- package/dist/hooks/usePayToAddressChainOptions.js +6 -13
- package/dist/hooks/usePayToAddressTokens.js +4 -15
- package/dist/hooks/usePayWithToken.js +7 -6
- package/dist/hooks/usePaymentLifecycle.d.ts +5 -1
- package/dist/hooks/usePaymentLifecycle.js +52 -46
- package/dist/hooks/usePaymentState.d.ts +4 -3
- package/dist/hooks/usePaymentState.js +34 -7
- package/dist/hooks/useTokenList.d.ts +182 -0
- package/dist/hooks/useTokenList.js +24 -0
- package/dist/hooks/useTokenOptions.js +1 -1
- package/dist/providers/paykit-provider.js +14 -7
- package/dist/types/routes.d.ts +15 -14
- package/dist/types/routes.js +15 -14
- package/package.json +3 -6
- package/dist/utils/item.d.ts +0 -5
- package/dist/utils/item.js +0 -6
|
@@ -3,23 +3,24 @@ import { PaymentRail, StepKind, } from "@coin-voyage/shared/types";
|
|
|
3
3
|
import { assert } from "@coin-voyage/shared/utils";
|
|
4
4
|
import { useBackendApi } from "../components/contexts/api";
|
|
5
5
|
import { fetchPaymentDetails } from "../lib/api/payment-details";
|
|
6
|
+
import { isCryptoPaymentData, isDepositStepData } from "@coin-voyage/shared/payment";
|
|
6
7
|
async function executeWalletStep({ actions, paymentData, senderAddr, step, }) {
|
|
7
8
|
if (step.kind === StepKind.KIND_TRANSACTION) {
|
|
8
|
-
assert(
|
|
9
|
+
assert(isCryptoPaymentData(step.data), "Transaction step is missing executable wallet data");
|
|
9
10
|
return actions.execute({
|
|
10
11
|
from: senderAddr,
|
|
11
|
-
paymentData: step.data
|
|
12
|
+
paymentData: step.data,
|
|
12
13
|
});
|
|
13
14
|
}
|
|
14
15
|
assert(step.kind === StepKind.KIND_DEPOSIT, "Unsupported wallet payment step");
|
|
15
|
-
assert(
|
|
16
|
+
assert(isDepositStepData(step.data), "Deposit step is missing a deposit address");
|
|
16
17
|
return actions.execute({
|
|
17
18
|
amount: BigInt(paymentData.src.currency_amount.raw_amount),
|
|
18
19
|
from: senderAddr,
|
|
19
|
-
to: step.deposit_address,
|
|
20
|
+
to: step.data.deposit_address,
|
|
20
21
|
chainId: paymentData.src.chain_id,
|
|
21
|
-
token:
|
|
22
|
-
? { address:
|
|
22
|
+
token: step.data.currency.address
|
|
23
|
+
? { address: step.data.currency.address, decimals: paymentData.src.decimals }
|
|
23
24
|
: undefined,
|
|
24
25
|
});
|
|
25
26
|
}
|
|
@@ -4,13 +4,17 @@ type PaymentLifecycleHandlers = {
|
|
|
4
4
|
onPaymentCompleted: ((event: PayOrderCompletedEvent) => void) | undefined;
|
|
5
5
|
onPaymentBounced: ((event: PayOrderRefundedEvent) => void) | undefined;
|
|
6
6
|
};
|
|
7
|
+
type PaymentLifecycleOptions = {
|
|
8
|
+
optimisticConfirmation?: boolean;
|
|
9
|
+
};
|
|
7
10
|
/**
|
|
8
11
|
* Handles payment lifecycle events of an order, such as started, completed, and bounced.
|
|
9
12
|
* @param {PayOrder | undefined} order The pay order to monitor.
|
|
10
13
|
* @param {PaymentLifecycleHandlers} handlers Handlers for payment lifecycle events.
|
|
14
|
+
* @param {PaymentLifecycleOptions} options Lifecycle behavior flags.
|
|
11
15
|
* @returns
|
|
12
16
|
*/
|
|
13
|
-
export declare function usePaymentLifecycle(order: PayOrder | undefined, handlers: PaymentLifecycleHandlers): {
|
|
17
|
+
export declare function usePaymentLifecycle(order: PayOrder | undefined, handlers: PaymentLifecycleHandlers, options?: PaymentLifecycleOptions): {
|
|
14
18
|
isStarted: boolean;
|
|
15
19
|
isFinalized: boolean;
|
|
16
20
|
order: PayOrder | undefined;
|
|
@@ -1,76 +1,82 @@
|
|
|
1
1
|
import { PayOrderMode, PayOrderStatus, } from "@coin-voyage/shared/types";
|
|
2
|
-
import { useEffect,
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
const COMPLETED_STATES = [PayOrderStatus.COMPLETED, PayOrderStatus.REFUNDED];
|
|
4
|
+
const STARTED_STATES = [
|
|
5
|
+
...COMPLETED_STATES,
|
|
6
|
+
PayOrderStatus.PARTIAL_PAYMENT,
|
|
7
|
+
PayOrderStatus.AWAITING_CONFIRMATION,
|
|
8
|
+
PayOrderStatus.OPTIMISTIC_CONFIRMED,
|
|
9
|
+
PayOrderStatus.EXECUTING_ORDER,
|
|
10
|
+
];
|
|
3
11
|
/**
|
|
4
12
|
* Handles payment lifecycle events of an order, such as started, completed, and bounced.
|
|
5
13
|
* @param {PayOrder | undefined} order The pay order to monitor.
|
|
6
14
|
* @param {PaymentLifecycleHandlers} handlers Handlers for payment lifecycle events.
|
|
15
|
+
* @param {PaymentLifecycleOptions} options Lifecycle behavior flags.
|
|
7
16
|
* @returns
|
|
8
17
|
*/
|
|
9
|
-
export function usePaymentLifecycle(order, handlers) {
|
|
18
|
+
export function usePaymentLifecycle(order, handlers, options = {}) {
|
|
10
19
|
const sentStart = useRef(false);
|
|
11
20
|
const sentComplete = useRef(false);
|
|
21
|
+
const currentOrderId = useRef(undefined);
|
|
12
22
|
const { onPaymentStarted, onPaymentCompleted, onPaymentBounced } = handlers;
|
|
23
|
+
const { optimisticConfirmation = true } = options;
|
|
24
|
+
const orderId = order?.id;
|
|
13
25
|
const orderStatus = order?.status;
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const finalizedStatus = [...completedStates];
|
|
32
|
-
if (isSale) {
|
|
33
|
-
finalizedStatus.push(PayOrderStatus.OPTIMISTIC_CONFIRMED, PayOrderStatus.EXECUTING_ORDER);
|
|
34
|
-
}
|
|
35
|
-
return finalizedStatus.includes(orderStatus);
|
|
36
|
-
}, [orderStatus, isSale, completedStates]);
|
|
26
|
+
const orderMetadata = order?.metadata;
|
|
27
|
+
const payment = order?.payment;
|
|
28
|
+
const allowOptimisticCompletion = optimisticConfirmation && order?.mode === PayOrderMode.SALE;
|
|
29
|
+
const isStarted = !!orderStatus && STARTED_STATES.includes(orderStatus);
|
|
30
|
+
const isFinalized = !!orderStatus &&
|
|
31
|
+
(COMPLETED_STATES.includes(orderStatus) ||
|
|
32
|
+
(allowOptimisticCompletion &&
|
|
33
|
+
(orderStatus === PayOrderStatus.OPTIMISTIC_CONFIRMED || orderStatus === PayOrderStatus.EXECUTING_ORDER)));
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!orderId)
|
|
36
|
+
return;
|
|
37
|
+
if (currentOrderId.current === orderId)
|
|
38
|
+
return;
|
|
39
|
+
currentOrderId.current = orderId;
|
|
40
|
+
sentStart.current = false;
|
|
41
|
+
sentComplete.current = false;
|
|
42
|
+
}, [orderId]);
|
|
37
43
|
useEffect(() => {
|
|
38
|
-
if (sentStart.current || !
|
|
44
|
+
if (sentStart.current || !orderId || !payment || !orderStatus || !isStarted)
|
|
39
45
|
return;
|
|
40
46
|
sentStart.current = true;
|
|
41
47
|
onPaymentStarted?.({
|
|
42
48
|
type: "payorder_confirming",
|
|
43
|
-
payorder_id:
|
|
44
|
-
status:
|
|
45
|
-
metadata:
|
|
46
|
-
payment_data:
|
|
49
|
+
payorder_id: orderId,
|
|
50
|
+
status: orderStatus,
|
|
51
|
+
metadata: orderMetadata,
|
|
52
|
+
payment_data: payment,
|
|
47
53
|
});
|
|
48
|
-
}, [
|
|
54
|
+
}, [isStarted, onPaymentStarted, orderId, orderMetadata, orderStatus, payment]);
|
|
49
55
|
useEffect(() => {
|
|
50
|
-
if (sentComplete.current || !
|
|
56
|
+
if (sentComplete.current || !orderId || !payment || !orderStatus || !isFinalized)
|
|
51
57
|
return;
|
|
52
58
|
sentComplete.current = true;
|
|
53
|
-
if (
|
|
59
|
+
if (orderStatus === PayOrderStatus.REFUNDED) {
|
|
54
60
|
onPaymentBounced?.({
|
|
55
61
|
type: "payorder_refunded",
|
|
56
|
-
payorder_id:
|
|
57
|
-
status:
|
|
58
|
-
metadata:
|
|
59
|
-
payment_data:
|
|
60
|
-
refund_address:
|
|
61
|
-
refund_tx_hash:
|
|
62
|
+
payorder_id: orderId,
|
|
63
|
+
status: orderStatus,
|
|
64
|
+
metadata: orderMetadata,
|
|
65
|
+
payment_data: payment,
|
|
66
|
+
refund_address: payment.refund_address ?? "",
|
|
67
|
+
refund_tx_hash: payment.refund_tx_hash ?? "",
|
|
62
68
|
});
|
|
63
69
|
return;
|
|
64
70
|
}
|
|
65
71
|
onPaymentCompleted?.({
|
|
66
72
|
type: "payorder_completed",
|
|
67
|
-
payorder_id:
|
|
68
|
-
status:
|
|
69
|
-
metadata:
|
|
70
|
-
payment_data:
|
|
71
|
-
source_tx_hash:
|
|
72
|
-
destination_tx_hash:
|
|
73
|
+
payorder_id: orderId,
|
|
74
|
+
status: orderStatus,
|
|
75
|
+
metadata: orderMetadata,
|
|
76
|
+
payment_data: payment,
|
|
77
|
+
source_tx_hash: payment.source_tx_hash ?? "",
|
|
78
|
+
destination_tx_hash: payment.destination_tx_hash ?? "",
|
|
73
79
|
});
|
|
74
|
-
}, [
|
|
80
|
+
}, [isFinalized, onPaymentBounced, onPaymentCompleted, orderId, orderMetadata, orderStatus, payment]);
|
|
75
81
|
return { isStarted, isFinalized, order };
|
|
76
82
|
}
|
|
@@ -5,10 +5,11 @@ import { CurrencyAndQuoteID } from "../types/state";
|
|
|
5
5
|
import { usePayOrderQuotes } from "./usePayOrderQuotes";
|
|
6
6
|
/** Loads a PayOrder + manages the corresponding modal. */
|
|
7
7
|
export interface PaymentState {
|
|
8
|
-
setPayId: (id: string | null) => Promise<
|
|
9
|
-
createDepositPayOrder: (params: PayOrderParams, onError?: (message: string) => void) => Promise<
|
|
8
|
+
setPayId: (id: string | null) => Promise<PayOrder | undefined>;
|
|
9
|
+
createDepositPayOrder: (params: PayOrderParams, onError?: (message: string) => void) => Promise<PayOrder | undefined>;
|
|
10
10
|
copyDepositPayOrder: () => Promise<void>;
|
|
11
11
|
clearUserSelection: () => void;
|
|
12
|
+
resetPaymentState: () => void;
|
|
12
13
|
payOrder: PayOrder | undefined;
|
|
13
14
|
paymentMethod: PaymentMethod | undefined;
|
|
14
15
|
setPaymentMethod: React.Dispatch<React.SetStateAction<PaymentMethod | undefined>>;
|
|
@@ -31,7 +32,7 @@ export interface PaymentState {
|
|
|
31
32
|
}
|
|
32
33
|
export declare function usePaymentState({ payOrder, setPayOrder, setRoute, log, }: {
|
|
33
34
|
payOrder: PayOrder | undefined;
|
|
34
|
-
setPayOrder: (o: PayOrder) => void;
|
|
35
|
+
setPayOrder: (o: PayOrder | undefined) => void;
|
|
35
36
|
setRoute: React.Dispatch<React.SetStateAction<ROUTE>>;
|
|
36
37
|
log: (...args: unknown[]) => void;
|
|
37
38
|
}): PaymentState;
|
|
@@ -15,7 +15,8 @@ export function usePaymentState({ payOrder, setPayOrder, setRoute, log, }) {
|
|
|
15
15
|
const api = useBackendApi();
|
|
16
16
|
const [connectorChainType, setConnectorChainType] = useState();
|
|
17
17
|
const [selectedWallet, setSelectedWallet] = useState();
|
|
18
|
-
const
|
|
18
|
+
const latestRequestedIdRef = useRef(null);
|
|
19
|
+
const inFlightPayOrderIdsRef = useRef(new Set());
|
|
19
20
|
const { account: senderAccount } = useAccount({
|
|
20
21
|
selectedWallet,
|
|
21
22
|
chainType: connectorChainType,
|
|
@@ -74,13 +75,23 @@ export function usePaymentState({ payOrder, setPayOrder, setRoute, log, }) {
|
|
|
74
75
|
const setPayOrderId = useCallback(async (payOrderId) => {
|
|
75
76
|
if (!payOrderId)
|
|
76
77
|
return;
|
|
77
|
-
if (
|
|
78
|
+
if (payOrder?.id === payOrderId)
|
|
78
79
|
return;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
if (inFlightPayOrderIdsRef.current.has(payOrderId))
|
|
81
|
+
return;
|
|
82
|
+
latestRequestedIdRef.current = payOrderId;
|
|
83
|
+
inFlightPayOrderIdsRef.current.add(payOrderId);
|
|
84
|
+
try {
|
|
85
|
+
const order = await fetchPayOrder(payOrderId);
|
|
86
|
+
if (order && latestRequestedIdRef.current === payOrderId) {
|
|
87
|
+
setPayOrder(order);
|
|
88
|
+
}
|
|
89
|
+
return order;
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
inFlightPayOrderIdsRef.current.delete(payOrderId);
|
|
93
|
+
}
|
|
94
|
+
}, [fetchPayOrder, payOrder?.id, setPayOrder]);
|
|
84
95
|
const copyDepositPayOrder = useCallback(async () => {
|
|
85
96
|
if (!payOrder?.id) {
|
|
86
97
|
log(`No payOrder to copy`);
|
|
@@ -124,10 +135,13 @@ export function usePaymentState({ payOrder, setPayOrder, setRoute, log, }) {
|
|
|
124
135
|
}
|
|
125
136
|
const { data: payOrder, error } = await api.createDepositPayOrder(params);
|
|
126
137
|
if (!payOrder || error) {
|
|
138
|
+
const errorMessage = error?.message || "Unable to create payment order";
|
|
139
|
+
onError?.(errorMessage);
|
|
127
140
|
log(`[CREATE DEPOSIT] Error creating payOrder: ${JSON.stringify(error)}`);
|
|
128
141
|
return;
|
|
129
142
|
}
|
|
130
143
|
setPayOrder(payOrder);
|
|
144
|
+
return payOrder;
|
|
131
145
|
}
|
|
132
146
|
catch (e) {
|
|
133
147
|
if (e instanceof Error)
|
|
@@ -142,11 +156,24 @@ export function usePaymentState({ payOrder, setPayOrder, setRoute, log, }) {
|
|
|
142
156
|
setSelectedWallet(undefined);
|
|
143
157
|
setRoute(ROUTE.SELECT_METHOD);
|
|
144
158
|
}, [setRoute]);
|
|
159
|
+
const resetPaymentState = useCallback(() => {
|
|
160
|
+
latestRequestedIdRef.current = null;
|
|
161
|
+
inFlightPayOrderIdsRef.current.clear();
|
|
162
|
+
setPayOrder(undefined);
|
|
163
|
+
setPaymentMethod(undefined);
|
|
164
|
+
setSelectedCurrencyOption(undefined);
|
|
165
|
+
setConnectorChainType(undefined);
|
|
166
|
+
setSelectedWallet(undefined);
|
|
167
|
+
setPayToAddressChainId(undefined);
|
|
168
|
+
setPayToAddressCurrency(undefined);
|
|
169
|
+
setRoute(ROUTE.SELECT_METHOD);
|
|
170
|
+
}, [setPayOrder, setRoute]);
|
|
145
171
|
return {
|
|
146
172
|
setPayId: setPayOrderId,
|
|
147
173
|
createDepositPayOrder,
|
|
148
174
|
copyDepositPayOrder,
|
|
149
175
|
clearUserSelection,
|
|
176
|
+
resetPaymentState,
|
|
150
177
|
payOrder,
|
|
151
178
|
paymentMethod,
|
|
152
179
|
setPaymentMethod,
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import type { ChainId } from "@coin-voyage/shared/types";
|
|
2
|
+
export declare function useTokenList(chainId?: ChainId): {
|
|
3
|
+
tokenList: import("@coin-voyage/shared/currency").TokenListResponse | undefined;
|
|
4
|
+
chains: import("@coin-voyage/shared/currency").ChainMetadata[];
|
|
5
|
+
tokens: import("@coin-voyage/shared/currency").Token[];
|
|
6
|
+
data: import("@coin-voyage/shared/currency").TokenListResponse;
|
|
7
|
+
error: Error;
|
|
8
|
+
isError: true;
|
|
9
|
+
isPending: false;
|
|
10
|
+
isLoading: false;
|
|
11
|
+
isLoadingError: false;
|
|
12
|
+
isRefetchError: true;
|
|
13
|
+
isSuccess: false;
|
|
14
|
+
isPlaceholderData: false;
|
|
15
|
+
status: "error";
|
|
16
|
+
dataUpdatedAt: number;
|
|
17
|
+
errorUpdatedAt: number;
|
|
18
|
+
failureCount: number;
|
|
19
|
+
failureReason: Error | null;
|
|
20
|
+
errorUpdateCount: number;
|
|
21
|
+
isFetched: boolean;
|
|
22
|
+
isFetchedAfterMount: boolean;
|
|
23
|
+
isFetching: boolean;
|
|
24
|
+
isInitialLoading: boolean;
|
|
25
|
+
isPaused: boolean;
|
|
26
|
+
isRefetching: boolean;
|
|
27
|
+
isStale: boolean;
|
|
28
|
+
isEnabled: boolean;
|
|
29
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@coin-voyage/shared/currency").TokenListResponse, Error>>;
|
|
30
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
31
|
+
promise: Promise<import("@coin-voyage/shared/currency").TokenListResponse>;
|
|
32
|
+
} | {
|
|
33
|
+
tokenList: import("@coin-voyage/shared/currency").TokenListResponse | undefined;
|
|
34
|
+
chains: import("@coin-voyage/shared/currency").ChainMetadata[];
|
|
35
|
+
tokens: import("@coin-voyage/shared/currency").Token[];
|
|
36
|
+
data: import("@coin-voyage/shared/currency").TokenListResponse;
|
|
37
|
+
error: null;
|
|
38
|
+
isError: false;
|
|
39
|
+
isPending: false;
|
|
40
|
+
isLoading: false;
|
|
41
|
+
isLoadingError: false;
|
|
42
|
+
isRefetchError: false;
|
|
43
|
+
isSuccess: true;
|
|
44
|
+
isPlaceholderData: false;
|
|
45
|
+
status: "success";
|
|
46
|
+
dataUpdatedAt: number;
|
|
47
|
+
errorUpdatedAt: number;
|
|
48
|
+
failureCount: number;
|
|
49
|
+
failureReason: Error | null;
|
|
50
|
+
errorUpdateCount: number;
|
|
51
|
+
isFetched: boolean;
|
|
52
|
+
isFetchedAfterMount: boolean;
|
|
53
|
+
isFetching: boolean;
|
|
54
|
+
isInitialLoading: boolean;
|
|
55
|
+
isPaused: boolean;
|
|
56
|
+
isRefetching: boolean;
|
|
57
|
+
isStale: boolean;
|
|
58
|
+
isEnabled: boolean;
|
|
59
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@coin-voyage/shared/currency").TokenListResponse, Error>>;
|
|
60
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
61
|
+
promise: Promise<import("@coin-voyage/shared/currency").TokenListResponse>;
|
|
62
|
+
} | {
|
|
63
|
+
tokenList: import("@coin-voyage/shared/currency").TokenListResponse | undefined;
|
|
64
|
+
chains: import("@coin-voyage/shared/currency").ChainMetadata[];
|
|
65
|
+
tokens: import("@coin-voyage/shared/currency").Token[];
|
|
66
|
+
data: undefined;
|
|
67
|
+
error: Error;
|
|
68
|
+
isError: true;
|
|
69
|
+
isPending: false;
|
|
70
|
+
isLoading: false;
|
|
71
|
+
isLoadingError: true;
|
|
72
|
+
isRefetchError: false;
|
|
73
|
+
isSuccess: false;
|
|
74
|
+
isPlaceholderData: false;
|
|
75
|
+
status: "error";
|
|
76
|
+
dataUpdatedAt: number;
|
|
77
|
+
errorUpdatedAt: number;
|
|
78
|
+
failureCount: number;
|
|
79
|
+
failureReason: Error | null;
|
|
80
|
+
errorUpdateCount: number;
|
|
81
|
+
isFetched: boolean;
|
|
82
|
+
isFetchedAfterMount: boolean;
|
|
83
|
+
isFetching: boolean;
|
|
84
|
+
isInitialLoading: boolean;
|
|
85
|
+
isPaused: boolean;
|
|
86
|
+
isRefetching: boolean;
|
|
87
|
+
isStale: boolean;
|
|
88
|
+
isEnabled: boolean;
|
|
89
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@coin-voyage/shared/currency").TokenListResponse, Error>>;
|
|
90
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
91
|
+
promise: Promise<import("@coin-voyage/shared/currency").TokenListResponse>;
|
|
92
|
+
} | {
|
|
93
|
+
tokenList: import("@coin-voyage/shared/currency").TokenListResponse | undefined;
|
|
94
|
+
chains: import("@coin-voyage/shared/currency").ChainMetadata[];
|
|
95
|
+
tokens: import("@coin-voyage/shared/currency").Token[];
|
|
96
|
+
data: undefined;
|
|
97
|
+
error: null;
|
|
98
|
+
isError: false;
|
|
99
|
+
isPending: true;
|
|
100
|
+
isLoading: true;
|
|
101
|
+
isLoadingError: false;
|
|
102
|
+
isRefetchError: false;
|
|
103
|
+
isSuccess: false;
|
|
104
|
+
isPlaceholderData: false;
|
|
105
|
+
status: "pending";
|
|
106
|
+
dataUpdatedAt: number;
|
|
107
|
+
errorUpdatedAt: number;
|
|
108
|
+
failureCount: number;
|
|
109
|
+
failureReason: Error | null;
|
|
110
|
+
errorUpdateCount: number;
|
|
111
|
+
isFetched: boolean;
|
|
112
|
+
isFetchedAfterMount: boolean;
|
|
113
|
+
isFetching: boolean;
|
|
114
|
+
isInitialLoading: boolean;
|
|
115
|
+
isPaused: boolean;
|
|
116
|
+
isRefetching: boolean;
|
|
117
|
+
isStale: boolean;
|
|
118
|
+
isEnabled: boolean;
|
|
119
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@coin-voyage/shared/currency").TokenListResponse, Error>>;
|
|
120
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
121
|
+
promise: Promise<import("@coin-voyage/shared/currency").TokenListResponse>;
|
|
122
|
+
} | {
|
|
123
|
+
tokenList: import("@coin-voyage/shared/currency").TokenListResponse | undefined;
|
|
124
|
+
chains: import("@coin-voyage/shared/currency").ChainMetadata[];
|
|
125
|
+
tokens: import("@coin-voyage/shared/currency").Token[];
|
|
126
|
+
data: undefined;
|
|
127
|
+
error: null;
|
|
128
|
+
isError: false;
|
|
129
|
+
isPending: true;
|
|
130
|
+
isLoadingError: false;
|
|
131
|
+
isRefetchError: false;
|
|
132
|
+
isSuccess: false;
|
|
133
|
+
isPlaceholderData: false;
|
|
134
|
+
status: "pending";
|
|
135
|
+
dataUpdatedAt: number;
|
|
136
|
+
errorUpdatedAt: number;
|
|
137
|
+
failureCount: number;
|
|
138
|
+
failureReason: Error | null;
|
|
139
|
+
errorUpdateCount: number;
|
|
140
|
+
isFetched: boolean;
|
|
141
|
+
isFetchedAfterMount: boolean;
|
|
142
|
+
isFetching: boolean;
|
|
143
|
+
isLoading: boolean;
|
|
144
|
+
isInitialLoading: boolean;
|
|
145
|
+
isPaused: boolean;
|
|
146
|
+
isRefetching: boolean;
|
|
147
|
+
isStale: boolean;
|
|
148
|
+
isEnabled: boolean;
|
|
149
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@coin-voyage/shared/currency").TokenListResponse, Error>>;
|
|
150
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
151
|
+
promise: Promise<import("@coin-voyage/shared/currency").TokenListResponse>;
|
|
152
|
+
} | {
|
|
153
|
+
tokenList: import("@coin-voyage/shared/currency").TokenListResponse | undefined;
|
|
154
|
+
chains: import("@coin-voyage/shared/currency").ChainMetadata[];
|
|
155
|
+
tokens: import("@coin-voyage/shared/currency").Token[];
|
|
156
|
+
data: import("@coin-voyage/shared/currency").TokenListResponse;
|
|
157
|
+
isError: false;
|
|
158
|
+
error: null;
|
|
159
|
+
isPending: false;
|
|
160
|
+
isLoading: false;
|
|
161
|
+
isLoadingError: false;
|
|
162
|
+
isRefetchError: false;
|
|
163
|
+
isSuccess: true;
|
|
164
|
+
isPlaceholderData: true;
|
|
165
|
+
status: "success";
|
|
166
|
+
dataUpdatedAt: number;
|
|
167
|
+
errorUpdatedAt: number;
|
|
168
|
+
failureCount: number;
|
|
169
|
+
failureReason: Error | null;
|
|
170
|
+
errorUpdateCount: number;
|
|
171
|
+
isFetched: boolean;
|
|
172
|
+
isFetchedAfterMount: boolean;
|
|
173
|
+
isFetching: boolean;
|
|
174
|
+
isInitialLoading: boolean;
|
|
175
|
+
isPaused: boolean;
|
|
176
|
+
isRefetching: boolean;
|
|
177
|
+
isStale: boolean;
|
|
178
|
+
isEnabled: boolean;
|
|
179
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@coin-voyage/shared/currency").TokenListResponse, Error>>;
|
|
180
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
181
|
+
promise: Promise<import("@coin-voyage/shared/currency").TokenListResponse>;
|
|
182
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { fetchTokenList, getChains, tokensByChainId } from "@coin-voyage/shared/currency";
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
const TOKEN_LIST_QUERY_KEY = ["token-list"];
|
|
5
|
+
const TOKEN_LIST_STALE_TIME = 1000 * 60 * 15;
|
|
6
|
+
export function useTokenList(chainId) {
|
|
7
|
+
const query = useQuery({
|
|
8
|
+
queryKey: TOKEN_LIST_QUERY_KEY,
|
|
9
|
+
queryFn: () => fetchTokenList(),
|
|
10
|
+
staleTime: TOKEN_LIST_STALE_TIME,
|
|
11
|
+
});
|
|
12
|
+
const chains = useMemo(() => getChains(query.data?.chains ?? []), [query.data]);
|
|
13
|
+
const tokens = useMemo(() => {
|
|
14
|
+
if (!query.data || !chainId)
|
|
15
|
+
return [];
|
|
16
|
+
return tokensByChainId(query.data.chains, chainId);
|
|
17
|
+
}, [query.data, chainId]);
|
|
18
|
+
return {
|
|
19
|
+
...query,
|
|
20
|
+
tokenList: query.data,
|
|
21
|
+
chains,
|
|
22
|
+
tokens,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -33,7 +33,7 @@ export function useTokenOptions(disabled) {
|
|
|
33
33
|
disabled: isDisabled,
|
|
34
34
|
iconShape: "squircle",
|
|
35
35
|
icons: [
|
|
36
|
-
_jsx(TokenChainLogo, { src: quote.image_uri, alt: quote.ticker
|
|
36
|
+
_jsx(TokenChainLogo, { src: quote.image_uri, alt: `${quote.ticker} logo`, chainId: quote.chain_id }, `${quote.ticker}-${quote.chain_id}`),
|
|
37
37
|
],
|
|
38
38
|
onClick: () => {
|
|
39
39
|
setSelectedCurrencyOption(quote);
|
|
@@ -62,6 +62,10 @@ function PayKitProviderInternal({ theme = "auto", mode = "auto", customTheme, op
|
|
|
62
62
|
const [resize, onResize] = useState(0);
|
|
63
63
|
const onOpenRef = useRef(undefined);
|
|
64
64
|
const onCloseRef = useRef(undefined);
|
|
65
|
+
const openRef = useRef(false);
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
openRef.current = open;
|
|
68
|
+
}, [open]);
|
|
65
69
|
const setOnOpen = useCallback((fn) => {
|
|
66
70
|
onOpenRef.current = fn;
|
|
67
71
|
}, []);
|
|
@@ -101,20 +105,23 @@ function PayKitProviderInternal({ theme = "auto", mode = "auto", customTheme, op
|
|
|
101
105
|
setErrorMessage(null);
|
|
102
106
|
}, [route, open]);
|
|
103
107
|
const resetAfterClose = useCallback(() => {
|
|
104
|
-
if (paymentCompleted
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
if (!paymentCompleted || !modalOptions?.resetOnSuccess)
|
|
109
|
+
return;
|
|
110
|
+
setPaymentCompleted(false);
|
|
111
|
+
paymentStateRef.current.resetPaymentState();
|
|
108
112
|
}, [modalOptions?.resetOnSuccess, paymentCompleted]);
|
|
109
113
|
const setOpen = useCallback((nextOpen) => {
|
|
114
|
+
if (openRef.current === nextOpen) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
openRef.current = nextOpen;
|
|
110
118
|
setOpenState(nextOpen);
|
|
111
119
|
if (nextOpen) {
|
|
112
120
|
onOpenRef.current?.();
|
|
113
121
|
return;
|
|
114
122
|
}
|
|
115
|
-
resetAfterClose();
|
|
116
123
|
onCloseRef.current?.();
|
|
117
|
-
}, [
|
|
124
|
+
}, []);
|
|
118
125
|
const onSuccess = useCallback(() => {
|
|
119
126
|
setPaymentCompleted(true);
|
|
120
127
|
if (modalOptions?.closeOnSuccess) {
|
|
@@ -247,7 +254,7 @@ function PayKitProviderInternal({ theme = "auto", mode = "auto", customTheme, op
|
|
|
247
254
|
paymentState,
|
|
248
255
|
allowedWallets,
|
|
249
256
|
};
|
|
250
|
-
return (_jsx(PayContext.Provider, { value: value, children: _jsxs(StyledThemeProvider, { theme: defaultTheme, children: [children, _jsx(PayModal, {})] }) }));
|
|
257
|
+
return (_jsx(PayContext.Provider, { value: value, children: _jsxs(StyledThemeProvider, { theme: defaultTheme, children: [children, _jsx(PayModal, { onExited: resetAfterClose })] }) }));
|
|
251
258
|
}
|
|
252
259
|
// === Helper functions ===
|
|
253
260
|
const NON_FINAL_PAY_ORDER_STATUSES = [PayOrderStatus.PENDING, PayOrderStatus.AWAITING_PAYMENT, PayOrderStatus.EXPIRED];
|
package/dist/types/routes.d.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
export declare enum ROUTE {
|
|
2
2
|
SELECT_METHOD = 0,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
PREPARING_PAYMENT = 1,
|
|
4
|
+
ADDRESS_CHAIN_SELECT = 2,
|
|
5
|
+
ADDRESS_TOKEN_SELECT = 3,
|
|
6
|
+
PAY_TO_ADDRESS = 4,
|
|
7
|
+
WALLET_CHAIN_SELECT = 5,
|
|
8
|
+
WALLET_TOKEN_SELECT = 6,
|
|
9
|
+
CONNECTORS = 7,
|
|
10
|
+
MOBILECONNECTORS = 8,
|
|
11
|
+
CONNECT = 9,
|
|
12
|
+
WALLET_PAYMENT = 10,
|
|
13
|
+
CARD_PAYMENT = 11,
|
|
14
|
+
CONFIRMATION = 12,
|
|
15
|
+
ONBOARDING = 13,
|
|
16
|
+
ABOUT = 14,
|
|
17
|
+
DOWNLOAD = 15
|
|
17
18
|
}
|
package/dist/types/routes.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
export var ROUTE;
|
|
2
2
|
(function (ROUTE) {
|
|
3
3
|
ROUTE[ROUTE["SELECT_METHOD"] = 0] = "SELECT_METHOD";
|
|
4
|
-
ROUTE[ROUTE["
|
|
5
|
-
ROUTE[ROUTE["
|
|
6
|
-
ROUTE[ROUTE["
|
|
7
|
-
ROUTE[ROUTE["
|
|
8
|
-
ROUTE[ROUTE["
|
|
9
|
-
ROUTE[ROUTE["
|
|
10
|
-
ROUTE[ROUTE["
|
|
11
|
-
ROUTE[ROUTE["
|
|
12
|
-
ROUTE[ROUTE["
|
|
13
|
-
ROUTE[ROUTE["
|
|
14
|
-
ROUTE[ROUTE["
|
|
4
|
+
ROUTE[ROUTE["PREPARING_PAYMENT"] = 1] = "PREPARING_PAYMENT";
|
|
5
|
+
ROUTE[ROUTE["ADDRESS_CHAIN_SELECT"] = 2] = "ADDRESS_CHAIN_SELECT";
|
|
6
|
+
ROUTE[ROUTE["ADDRESS_TOKEN_SELECT"] = 3] = "ADDRESS_TOKEN_SELECT";
|
|
7
|
+
ROUTE[ROUTE["PAY_TO_ADDRESS"] = 4] = "PAY_TO_ADDRESS";
|
|
8
|
+
ROUTE[ROUTE["WALLET_CHAIN_SELECT"] = 5] = "WALLET_CHAIN_SELECT";
|
|
9
|
+
ROUTE[ROUTE["WALLET_TOKEN_SELECT"] = 6] = "WALLET_TOKEN_SELECT";
|
|
10
|
+
ROUTE[ROUTE["CONNECTORS"] = 7] = "CONNECTORS";
|
|
11
|
+
ROUTE[ROUTE["MOBILECONNECTORS"] = 8] = "MOBILECONNECTORS";
|
|
12
|
+
ROUTE[ROUTE["CONNECT"] = 9] = "CONNECT";
|
|
13
|
+
ROUTE[ROUTE["WALLET_PAYMENT"] = 10] = "WALLET_PAYMENT";
|
|
14
|
+
ROUTE[ROUTE["CARD_PAYMENT"] = 11] = "CARD_PAYMENT";
|
|
15
|
+
ROUTE[ROUTE["CONFIRMATION"] = 12] = "CONFIRMATION";
|
|
15
16
|
// Other
|
|
16
|
-
ROUTE[ROUTE["ONBOARDING"] =
|
|
17
|
-
ROUTE[ROUTE["ABOUT"] =
|
|
18
|
-
ROUTE[ROUTE["DOWNLOAD"] =
|
|
17
|
+
ROUTE[ROUTE["ONBOARDING"] = 13] = "ONBOARDING";
|
|
18
|
+
ROUTE[ROUTE["ABOUT"] = 14] = "ABOUT";
|
|
19
|
+
ROUTE[ROUTE["DOWNLOAD"] = 15] = "DOWNLOAD";
|
|
19
20
|
})(ROUTE || (ROUTE = {}));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coin-voyage/paykit",
|
|
3
3
|
"description": "Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.",
|
|
4
|
-
"version": "2.4.
|
|
4
|
+
"version": "2.4.4-beta.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"author": "Lars <lars@coinvoyage.io>",
|
|
@@ -31,9 +31,6 @@
|
|
|
31
31
|
],
|
|
32
32
|
"server": [
|
|
33
33
|
"dist/server.d.ts"
|
|
34
|
-
],
|
|
35
|
-
"client": [
|
|
36
|
-
"dist/client.d.ts"
|
|
37
34
|
]
|
|
38
35
|
}
|
|
39
36
|
},
|
|
@@ -63,8 +60,8 @@
|
|
|
63
60
|
"@stripe/crypto": "0.0.4",
|
|
64
61
|
"styled-components": "^5.3.11",
|
|
65
62
|
"uuid": "13.0.0",
|
|
66
|
-
"@coin-voyage/shared": "2.4.
|
|
67
|
-
"@coin-voyage/crypto": "2.4.3
|
|
63
|
+
"@coin-voyage/shared": "2.4.4-beta.1",
|
|
64
|
+
"@coin-voyage/crypto": "2.4.3"
|
|
68
65
|
},
|
|
69
66
|
"devDependencies": {
|
|
70
67
|
"@types/qrcode": "1.5.5",
|