@0xsequence/marketplace-sdk 0.4.2 → 0.4.4
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-ZWIRTV7A.js → chunk-4VS5NKDD.js} +2 -2
- package/dist/{chunk-GSDUAHL3.js → chunk-6WB4GCCJ.js} +1 -1
- package/dist/chunk-6WB4GCCJ.js.map +1 -0
- package/dist/{chunk-MTFS5SED.js → chunk-6XUCLBZC.js} +3093 -2463
- package/dist/chunk-6XUCLBZC.js.map +1 -0
- package/dist/{chunk-T5T6JNB2.js → chunk-ATDCYXXV.js} +49 -49
- package/dist/chunk-ATDCYXXV.js.map +1 -0
- package/dist/{chunk-LSMQVX77.js → chunk-CP2IVRMX.js} +2 -2
- package/dist/{chunk-OPMDGQFB.js → chunk-DNDPYQKV.js} +20 -2
- package/dist/chunk-DNDPYQKV.js.map +1 -0
- package/dist/{chunk-WBJKZOQ7.js → chunk-GLOIEUWC.js} +225 -364
- package/dist/chunk-GLOIEUWC.js.map +1 -0
- package/dist/{chunk-4RKM3VUV.js → chunk-IQXJZBMR.js} +2 -2
- package/dist/{chunk-MQ5WSFDH.js → chunk-J4TRSLTB.js} +29 -4
- package/dist/chunk-J4TRSLTB.js.map +1 -0
- package/dist/chunk-LHN6EBLM.js +420 -0
- package/dist/chunk-LHN6EBLM.js.map +1 -0
- package/dist/{chunk-WQCWBXBM.js → chunk-PAZ4MQXZ.js} +1 -1
- package/dist/chunk-PAZ4MQXZ.js.map +1 -0
- package/dist/{chunk-S5IPE7TH.js → chunk-URX7ZHX4.js} +2 -2
- package/dist/chunk-Y75XGZOB.js +11 -0
- package/dist/chunk-Y75XGZOB.js.map +1 -0
- package/dist/{chunk-Q2BVDQ3G.js → chunk-ZEKRTFBU.js} +1 -1
- package/dist/{chunk-Q2BVDQ3G.js.map → chunk-ZEKRTFBU.js.map} +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +10 -8
- package/dist/index.js.map +1 -1
- package/dist/react/_internal/api/index.js +2 -2
- package/dist/react/_internal/index.d.ts +1 -1
- package/dist/react/_internal/index.js +4 -4
- package/dist/react/_internal/wagmi/index.js +2 -2
- package/dist/react/hooks/index.d.ts +54 -42
- package/dist/react/hooks/index.js +8 -6
- package/dist/react/index.css +24 -24
- package/dist/react/index.css.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +11 -9
- package/dist/react/ssr/index.js.map +1 -1
- package/dist/react/ui/components/index.css +24 -24
- package/dist/react/ui/components/index.css.map +1 -1
- package/dist/react/ui/components/index.d.ts +1 -1
- package/dist/react/ui/components/index.js +11 -9
- package/dist/react/ui/icons/index.js +1 -1
- package/dist/react/ui/index.css +24 -24
- package/dist/react/ui/index.css.map +1 -1
- package/dist/react/ui/index.d.ts +5 -2
- package/dist/react/ui/index.js +11 -9
- package/dist/react/ui/modals/_internal/components/actionModal/index.css +46 -0
- package/dist/react/ui/modals/_internal/components/actionModal/index.css.map +1 -1
- package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +1 -1
- package/dist/react/ui/modals/_internal/components/actionModal/index.js +11 -6
- package/dist/types/index.js +4 -4
- package/dist/{types-BlDoGvJV.d.ts → types-DZb7GsfL.d.ts} +10 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +2 -2
- package/package.json +1 -1
- package/src/consts.ts +3 -0
- package/src/react/_internal/transaction-machine/useTransactionMachine.ts +9 -12
- package/src/react/_internal/transaction-machine/useWallet.ts +58 -0
- package/src/react/_internal/transaction-machine/wallet.ts +60 -3
- package/src/react/_internal/types.ts +11 -0
- package/src/react/hooks/useCancelOrder.tsx +26 -30
- package/src/react/hooks/useCancelTransactionSteps.tsx +222 -0
- package/src/react/hooks/useGetReceiptFromHash.tsx +32 -0
- package/src/react/ui/modals/BuyModal/Modal.tsx +97 -0
- package/src/react/ui/modals/BuyModal/hooks/useBuyCollectable.ts +109 -0
- package/src/react/ui/modals/BuyModal/hooks/useCheckoutOptions.ts +50 -0
- package/src/react/ui/modals/BuyModal/hooks/useFees.ts +38 -0
- package/src/react/ui/modals/BuyModal/hooks/useLoadData.ts +58 -0
- package/src/react/ui/modals/BuyModal/index.tsx +3 -210
- package/src/react/ui/modals/BuyModal/modals/CheckoutModal.tsx +29 -0
- package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +84 -0
- package/src/react/ui/modals/CreateListingModal/Modal.tsx +150 -207
- package/src/react/ui/modals/CreateListingModal/hooks/useCreateListing.tsx +62 -0
- package/src/react/ui/modals/CreateListingModal/hooks/useGetTokenApproval.ts +75 -0
- package/src/react/ui/modals/CreateListingModal/hooks/useTransactionSteps.tsx +216 -0
- package/src/react/ui/modals/CreateListingModal/index.tsx +1 -1
- package/src/react/ui/modals/CreateListingModal/store.ts +17 -9
- package/src/react/ui/modals/MakeOfferModal/Modal.tsx +173 -215
- package/src/react/ui/modals/MakeOfferModal/hooks/useGetTokenApproval.tsx +76 -0
- package/src/react/ui/modals/MakeOfferModal/hooks/useMakeOffer.tsx +62 -0
- package/src/react/ui/modals/MakeOfferModal/hooks/useTransactionSteps.tsx +225 -0
- package/src/react/ui/modals/MakeOfferModal/store.ts +15 -2
- package/src/react/ui/modals/SellModal/Modal.tsx +117 -190
- package/src/react/ui/modals/SellModal/hooks/useGetTokenApproval.tsx +73 -0
- package/src/react/ui/modals/SellModal/hooks/useSell.tsx +65 -0
- package/src/react/ui/modals/SellModal/hooks/useTransactionSteps.tsx +224 -0
- package/src/react/ui/modals/SellModal/store.ts +14 -1
- package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +26 -1
- package/src/react/ui/modals/_internal/components/currencyImage/index.tsx +8 -10
- package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +9 -1
- package/src/react/ui/modals/_internal/components/priceInput/hooks/useBalanceCheck.ts +67 -0
- package/src/react/ui/modals/_internal/components/priceInput/hooks/usePriceInput.ts +54 -0
- package/src/react/ui/modals/_internal/components/priceInput/index.tsx +49 -62
- package/src/react/ui/modals/_internal/components/switchChainModal/index.tsx +9 -4
- package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +3 -3
- package/src/react/ui/modals/_internal/types.ts +1 -1
- package/src/react/ui/modals/modal-provider.tsx +1 -1
- package/src/utils/_internal/error/transaction.ts +21 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/chunk-GSDUAHL3.js.map +0 -1
- package/dist/chunk-MQ5WSFDH.js.map +0 -1
- package/dist/chunk-MTFS5SED.js.map +0 -1
- package/dist/chunk-OPMDGQFB.js.map +0 -1
- package/dist/chunk-T5T6JNB2.js.map +0 -1
- package/dist/chunk-WBJKZOQ7.js.map +0 -1
- package/dist/chunk-WQCWBXBM.js.map +0 -1
- package/src/react/hooks/useCreateListing.tsx +0 -125
- package/src/react/hooks/useMakeOffer.tsx +0 -122
- package/src/react/hooks/useSell.tsx +0 -121
- /package/dist/{chunk-ZWIRTV7A.js.map → chunk-4VS5NKDD.js.map} +0 -0
- /package/dist/{chunk-LSMQVX77.js.map → chunk-CP2IVRMX.js.map} +0 -0
- /package/dist/{chunk-4RKM3VUV.js.map → chunk-IQXJZBMR.js.map} +0 -0
- /package/dist/{chunk-S5IPE7TH.js.map → chunk-URX7ZHX4.js.map} +0 -0
- /package/src/react/ui/modals/BuyModal/{_store.ts → store.ts} +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Observable } from '@legendapp/state';
|
|
2
|
+
import { ModalCallbacks } from '../../_internal/types';
|
|
3
|
+
import { useGetTokenApprovalData } from './useGetTokenApproval';
|
|
4
|
+
import { useTransactionSteps } from './useTransactionSteps';
|
|
5
|
+
import { useEffect } from 'react';
|
|
6
|
+
import {
|
|
7
|
+
MarketplaceKind,
|
|
8
|
+
OrderData,
|
|
9
|
+
TransactionSteps,
|
|
10
|
+
} from '../../../../_internal';
|
|
11
|
+
|
|
12
|
+
interface UseSellArgs {
|
|
13
|
+
collectibleId: string;
|
|
14
|
+
chainId: string;
|
|
15
|
+
collectionAddress: string;
|
|
16
|
+
marketplace: MarketplaceKind;
|
|
17
|
+
ordersData: Array<OrderData>;
|
|
18
|
+
callbacks?: ModalCallbacks;
|
|
19
|
+
closeMainModal: () => void;
|
|
20
|
+
steps$: Observable<TransactionSteps>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const useSell = ({
|
|
24
|
+
collectibleId,
|
|
25
|
+
chainId,
|
|
26
|
+
collectionAddress,
|
|
27
|
+
marketplace,
|
|
28
|
+
ordersData,
|
|
29
|
+
callbacks,
|
|
30
|
+
closeMainModal,
|
|
31
|
+
steps$,
|
|
32
|
+
}: UseSellArgs) => {
|
|
33
|
+
const { data: tokenApproval, isLoading: tokenApprovalIsLoading } =
|
|
34
|
+
useGetTokenApprovalData({
|
|
35
|
+
chainId,
|
|
36
|
+
collectionAddress,
|
|
37
|
+
ordersData,
|
|
38
|
+
marketplace,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (tokenApproval?.step && !tokenApprovalIsLoading) {
|
|
43
|
+
steps$.approval.exist.set(true);
|
|
44
|
+
}
|
|
45
|
+
}, [tokenApproval?.step, tokenApprovalIsLoading]);
|
|
46
|
+
|
|
47
|
+
const { generatingSteps, executeApproval, sell } = useTransactionSteps({
|
|
48
|
+
collectibleId,
|
|
49
|
+
chainId,
|
|
50
|
+
collectionAddress,
|
|
51
|
+
marketplace,
|
|
52
|
+
ordersData,
|
|
53
|
+
callbacks,
|
|
54
|
+
closeMainModal,
|
|
55
|
+
steps$,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
isLoading: generatingSteps,
|
|
60
|
+
executeApproval,
|
|
61
|
+
sell,
|
|
62
|
+
tokenApprovalStepExists: tokenApproval?.step !== null,
|
|
63
|
+
tokenApprovalIsLoading,
|
|
64
|
+
};
|
|
65
|
+
};
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ExecuteType,
|
|
3
|
+
getMarketplaceClient,
|
|
4
|
+
MarketplaceKind,
|
|
5
|
+
OrderData,
|
|
6
|
+
Step,
|
|
7
|
+
StepType,
|
|
8
|
+
TransactionSteps,
|
|
9
|
+
} from '../../../../_internal';
|
|
10
|
+
import { ModalCallbacks } from '../../_internal/types';
|
|
11
|
+
import { TransactionType } from '../../../../_internal/transaction-machine/execute-transaction';
|
|
12
|
+
import { useTransactionStatusModal } from '../../_internal/components/transactionStatusModal';
|
|
13
|
+
import { Address } from 'viem';
|
|
14
|
+
import { Observable } from '@legendapp/state';
|
|
15
|
+
import { useWallet } from '../../../../_internal/transaction-machine/useWallet';
|
|
16
|
+
import { SignatureStep } from '../../../../_internal/transaction-machine/utils';
|
|
17
|
+
import { useGetReceiptFromHash } from '../../../../hooks/useGetReceiptFromHash';
|
|
18
|
+
import { useConfig, useGenerateSellTransaction } from '../../../../hooks';
|
|
19
|
+
import { useFees } from '../../BuyModal/hooks/useFees';
|
|
20
|
+
|
|
21
|
+
export type ExecutionState = 'approval' | 'sell' | null;
|
|
22
|
+
|
|
23
|
+
interface UseTransactionStepsArgs {
|
|
24
|
+
collectibleId: string;
|
|
25
|
+
chainId: string;
|
|
26
|
+
collectionAddress: string;
|
|
27
|
+
marketplace: MarketplaceKind;
|
|
28
|
+
ordersData: Array<OrderData>;
|
|
29
|
+
callbacks?: ModalCallbacks;
|
|
30
|
+
closeMainModal: () => void;
|
|
31
|
+
steps$: Observable<TransactionSteps>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const useTransactionSteps = ({
|
|
35
|
+
collectibleId,
|
|
36
|
+
chainId,
|
|
37
|
+
collectionAddress,
|
|
38
|
+
marketplace,
|
|
39
|
+
ordersData,
|
|
40
|
+
callbacks,
|
|
41
|
+
closeMainModal,
|
|
42
|
+
steps$,
|
|
43
|
+
}: UseTransactionStepsArgs) => {
|
|
44
|
+
const { wallet } = useWallet();
|
|
45
|
+
const { show: showTransactionStatusModal } = useTransactionStatusModal();
|
|
46
|
+
const sdkConfig = useConfig();
|
|
47
|
+
const marketplaceClient = getMarketplaceClient(chainId, sdkConfig);
|
|
48
|
+
const { waitForReceipt } = useGetReceiptFromHash();
|
|
49
|
+
const { amount, receiver } = useFees({
|
|
50
|
+
chainId: Number(chainId),
|
|
51
|
+
collectionAddress: collectionAddress,
|
|
52
|
+
});
|
|
53
|
+
const { generateSellTransactionAsync, isPending: generatingSteps } =
|
|
54
|
+
useGenerateSellTransaction({
|
|
55
|
+
chainId,
|
|
56
|
+
onSuccess: (steps) => {
|
|
57
|
+
if (!steps) return;
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const getSellSteps = async () => {
|
|
62
|
+
if (!wallet) return;
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const address = await wallet.address();
|
|
66
|
+
|
|
67
|
+
const steps = await generateSellTransactionAsync({
|
|
68
|
+
collectionAddress,
|
|
69
|
+
walletType: wallet.walletKind,
|
|
70
|
+
marketplace,
|
|
71
|
+
ordersData,
|
|
72
|
+
additionalFees: [
|
|
73
|
+
{
|
|
74
|
+
amount,
|
|
75
|
+
receiver,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
seller: address,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return steps;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
if (callbacks?.onError) {
|
|
84
|
+
callbacks.onError(error as Error);
|
|
85
|
+
} else {
|
|
86
|
+
console.debug('onError callback not provided:', error);
|
|
87
|
+
}
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const executeApproval = async () => {
|
|
93
|
+
if (!wallet) return;
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
steps$.approval.isExecuting.set(true);
|
|
97
|
+
const approvalStep = await getSellSteps().then((steps) =>
|
|
98
|
+
steps?.find((step) => step.id === StepType.tokenApproval),
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const hash = await wallet.handleSendTransactionStep(
|
|
102
|
+
Number(chainId),
|
|
103
|
+
approvalStep as any,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const receipt = await waitForReceipt(hash);
|
|
107
|
+
|
|
108
|
+
if (receipt) {
|
|
109
|
+
steps$.approval.isExecuting.set(false);
|
|
110
|
+
steps$.approval.exist.set(false);
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
steps$.approval.isExecuting.set(false);
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const sell = async () => {
|
|
119
|
+
if (!wallet) return;
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
steps$.transaction.isExecuting.set(true);
|
|
123
|
+
const steps = await getSellSteps();
|
|
124
|
+
const transactionStep = steps?.find((step) => step.id === StepType.sell);
|
|
125
|
+
const signatureStep = steps?.find(
|
|
126
|
+
(step) => step.id === StepType.signEIP712,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
console.debug('transactionStep', transactionStep);
|
|
130
|
+
console.debug('signatureStep', signatureStep);
|
|
131
|
+
|
|
132
|
+
if (!transactionStep && !signatureStep) {
|
|
133
|
+
throw new Error('No transaction or signature step found');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let hash, orderId: string | undefined;
|
|
137
|
+
|
|
138
|
+
if (transactionStep) {
|
|
139
|
+
hash = await executeTransaction({ transactionStep });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (signatureStep) {
|
|
143
|
+
orderId = await executeSignature({ signatureStep });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
closeMainModal();
|
|
147
|
+
|
|
148
|
+
showTransactionStatusModal({
|
|
149
|
+
type: TransactionType.SELL,
|
|
150
|
+
collectionAddress: collectionAddress as Address,
|
|
151
|
+
chainId,
|
|
152
|
+
collectibleId,
|
|
153
|
+
hash,
|
|
154
|
+
orderId,
|
|
155
|
+
callbacks,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
if (hash) {
|
|
159
|
+
await waitForReceipt(hash);
|
|
160
|
+
steps$.transaction.isExecuting.set(false);
|
|
161
|
+
steps$.transaction.exist.set(false);
|
|
162
|
+
if (callbacks?.onSuccess && typeof callbacks.onSuccess === 'function') {
|
|
163
|
+
callbacks.onSuccess({ hash });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (orderId) {
|
|
168
|
+
// no need to wait for receipt, because the order is already created
|
|
169
|
+
|
|
170
|
+
steps$.transaction.isExecuting.set(false);
|
|
171
|
+
steps$.transaction.exist.set(false);
|
|
172
|
+
|
|
173
|
+
if (callbacks?.onSuccess && typeof callbacks.onSuccess === 'function') {
|
|
174
|
+
callbacks.onSuccess({ orderId });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
steps$.transaction.isExecuting.set(false);
|
|
179
|
+
steps$.transaction.exist.set(false);
|
|
180
|
+
if (callbacks?.onError && typeof callbacks.onError === 'function') {
|
|
181
|
+
callbacks.onError(error as Error);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const executeTransaction = async ({
|
|
189
|
+
transactionStep,
|
|
190
|
+
}: { transactionStep: Step }) => {
|
|
191
|
+
if (!wallet) return;
|
|
192
|
+
|
|
193
|
+
const hash = await wallet.handleSendTransactionStep(
|
|
194
|
+
Number(chainId),
|
|
195
|
+
transactionStep as any,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
return hash;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const executeSignature = async ({
|
|
202
|
+
signatureStep,
|
|
203
|
+
}: { signatureStep: Step }) => {
|
|
204
|
+
if (!wallet) return;
|
|
205
|
+
|
|
206
|
+
const signature = await wallet.handleSignMessageStep(
|
|
207
|
+
signatureStep as SignatureStep,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const result = await marketplaceClient.execute({
|
|
211
|
+
signature: signature as string,
|
|
212
|
+
executeType: ExecuteType.order,
|
|
213
|
+
body: signatureStep.post?.body,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
return result.orderId;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
generatingSteps,
|
|
221
|
+
executeApproval,
|
|
222
|
+
sell,
|
|
223
|
+
};
|
|
224
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { observable } from '@legendapp/state';
|
|
2
2
|
import type { Hex } from 'viem';
|
|
3
|
-
import type { Order } from '../../../_internal';
|
|
3
|
+
import type { Order, TransactionSteps } from '../../../_internal';
|
|
4
4
|
import type { BaseModalState, ModalCallbacks } from '../_internal/types';
|
|
5
5
|
|
|
6
6
|
export type OpenSellModalArgs = {
|
|
@@ -14,6 +14,7 @@ export type OpenSellModalArgs = {
|
|
|
14
14
|
type SellModalState = BaseModalState & {
|
|
15
15
|
tokenId: string;
|
|
16
16
|
order?: Order;
|
|
17
|
+
steps: TransactionSteps;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
type Actions = {
|
|
@@ -42,6 +43,18 @@ const initialState: SellModalState & Actions = {
|
|
|
42
43
|
sellModal$.isOpen.set(false);
|
|
43
44
|
sellModal$.callbacks.set(undefined);
|
|
44
45
|
},
|
|
46
|
+
steps: {
|
|
47
|
+
approval: {
|
|
48
|
+
exist: false,
|
|
49
|
+
isExecuting: false,
|
|
50
|
+
execute: () => Promise.resolve(),
|
|
51
|
+
},
|
|
52
|
+
transaction: {
|
|
53
|
+
exist: false,
|
|
54
|
+
isExecuting: false,
|
|
55
|
+
execute: () => Promise.resolve(),
|
|
56
|
+
},
|
|
57
|
+
},
|
|
45
58
|
};
|
|
46
59
|
|
|
47
60
|
export const sellModal$ = observable(initialState);
|
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
dialogOverlay,
|
|
22
22
|
} from './styles.css';
|
|
23
23
|
import WaasFeeOptionsBox from '../waasFeeOptionsBox';
|
|
24
|
+
import { useSwitchChainModal } from '../switchChainModal';
|
|
25
|
+
import { useWallet } from '../../../../../_internal/transaction-machine/useWallet';
|
|
24
26
|
|
|
25
27
|
export interface ActionModalProps {
|
|
26
28
|
isOpen: boolean;
|
|
@@ -41,6 +43,25 @@ export interface ActionModalProps {
|
|
|
41
43
|
export const ActionModal = observer(
|
|
42
44
|
({ isOpen, onClose, title, children, ctas, chainId }: ActionModalProps) => {
|
|
43
45
|
const [isSelectingFees, setIsSelectingFees] = useState(false);
|
|
46
|
+
const { show: showSwitchChainModal } = useSwitchChainModal();
|
|
47
|
+
const { wallet } = useWallet();
|
|
48
|
+
|
|
49
|
+
const checkChain = async ({ onSuccess }: { onSuccess: () => void }) => {
|
|
50
|
+
const walletChainId = await wallet?.getChainId();
|
|
51
|
+
const chainMismatch = walletChainId !== Number(chainId);
|
|
52
|
+
if (chainMismatch) {
|
|
53
|
+
showSwitchChainModal({
|
|
54
|
+
chainIdToSwitchTo: Number(chainId),
|
|
55
|
+
onSuccess,
|
|
56
|
+
});
|
|
57
|
+
} else {
|
|
58
|
+
onSuccess();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (wallet?.isWaaS) {
|
|
63
|
+
wallet.switchChain(Number(chainId));
|
|
64
|
+
}
|
|
44
65
|
|
|
45
66
|
return (
|
|
46
67
|
<Root open={isOpen && !!chainId}>
|
|
@@ -76,7 +97,11 @@ export const ActionModal = observer(
|
|
|
76
97
|
key={cta.label}
|
|
77
98
|
className={ctaStyle}
|
|
78
99
|
onClick={async () => {
|
|
79
|
-
await
|
|
100
|
+
await checkChain({
|
|
101
|
+
onSuccess: () => {
|
|
102
|
+
cta.onClick();
|
|
103
|
+
},
|
|
104
|
+
});
|
|
80
105
|
}}
|
|
81
106
|
variant={cta.variant || 'primary'}
|
|
82
107
|
pending={cta.pending}
|
|
@@ -4,15 +4,13 @@ import { useState } from 'react';
|
|
|
4
4
|
import type { Address } from 'viem';
|
|
5
5
|
import type { Price } from '../../../../../../types';
|
|
6
6
|
|
|
7
|
-
function CurrencyImage({
|
|
8
|
-
$listingPrice,
|
|
9
|
-
}: { $listingPrice: Observable<Price | undefined> }) {
|
|
7
|
+
function CurrencyImage({ price$ }: { price$: Observable<Price | undefined> }) {
|
|
10
8
|
const [imageLoadErrorCurrencyAddresses, setImageLoadErrorCurrencyAddresses] =
|
|
11
9
|
useState<Address[] | null>(null);
|
|
12
10
|
|
|
13
11
|
if (
|
|
14
12
|
imageLoadErrorCurrencyAddresses?.includes(
|
|
15
|
-
|
|
13
|
+
price$.currency.contractAddress.get() as Address,
|
|
16
14
|
)
|
|
17
15
|
) {
|
|
18
16
|
return (
|
|
@@ -27,19 +25,19 @@ function CurrencyImage({
|
|
|
27
25
|
|
|
28
26
|
return (
|
|
29
27
|
<TokenImage
|
|
30
|
-
src={
|
|
28
|
+
src={price$.currency.imageUrl.get()}
|
|
31
29
|
onError={() => {
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
30
|
+
const price = price$?.get();
|
|
31
|
+
if (price) {
|
|
34
32
|
setImageLoadErrorCurrencyAddresses((prev) => {
|
|
35
33
|
if (!prev)
|
|
36
|
-
return [
|
|
34
|
+
return [price$.currency.contractAddress.get() as Address];
|
|
37
35
|
if (
|
|
38
|
-
!prev.includes(
|
|
36
|
+
!prev.includes(price$.currency.contractAddress.get() as Address)
|
|
39
37
|
) {
|
|
40
38
|
return [
|
|
41
39
|
...prev,
|
|
42
|
-
|
|
40
|
+
price$.currency.contractAddress.get() as Address,
|
|
43
41
|
];
|
|
44
42
|
}
|
|
45
43
|
return prev;
|
|
@@ -15,11 +15,13 @@ type CurrencyOptionsSelectProps = {
|
|
|
15
15
|
collectionAddress: Hex;
|
|
16
16
|
chainId: ChainId;
|
|
17
17
|
selectedCurrency$: Observable<Currency | null | undefined>;
|
|
18
|
+
secondCurrencyAsDefault?: boolean;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
const CurrencyOptionsSelect = observer(function CurrencyOptionsSelect({
|
|
21
22
|
chainId,
|
|
22
23
|
collectionAddress,
|
|
24
|
+
secondCurrencyAsDefault,
|
|
23
25
|
selectedCurrency$,
|
|
24
26
|
}: CurrencyOptionsSelectProps) {
|
|
25
27
|
const currency = selectedCurrency$.get() as Currency;
|
|
@@ -37,7 +39,13 @@ const CurrencyOptionsSelect = observer(function CurrencyOptionsSelect({
|
|
|
37
39
|
currencies.length > 0 &&
|
|
38
40
|
!selectedCurrency$.get()?.contractAddress
|
|
39
41
|
) {
|
|
40
|
-
|
|
42
|
+
// We dont support native currency listings for any marketplace other than Sequence Marketplace v2
|
|
43
|
+
// So we need to set the set another currency as the default
|
|
44
|
+
if (secondCurrencyAsDefault) {
|
|
45
|
+
selectedCurrency$.set(currencies[1]);
|
|
46
|
+
} else {
|
|
47
|
+
selectedCurrency$.set(currencies[0]);
|
|
48
|
+
}
|
|
41
49
|
}
|
|
42
50
|
}, [currencies]);
|
|
43
51
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type Observable } from '@legendapp/state';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import type { Hex } from 'viem';
|
|
4
|
+
import type { Price } from '../../../../../../../types';
|
|
5
|
+
import { useCurrencyBalance } from '../../../../../../hooks/useCurrencyBalance';
|
|
6
|
+
|
|
7
|
+
type UseBalanceCheckProps = {
|
|
8
|
+
checkBalance?: {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
callback: (state: boolean) => void;
|
|
11
|
+
};
|
|
12
|
+
price$: Observable<Price | undefined>;
|
|
13
|
+
currencyAddress: Hex;
|
|
14
|
+
chainId: number;
|
|
15
|
+
userAddress: Hex;
|
|
16
|
+
currencyDecimals: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const useBalanceCheck = ({
|
|
20
|
+
checkBalance,
|
|
21
|
+
price$,
|
|
22
|
+
currencyAddress,
|
|
23
|
+
chainId,
|
|
24
|
+
userAddress,
|
|
25
|
+
currencyDecimals,
|
|
26
|
+
}: UseBalanceCheckProps) => {
|
|
27
|
+
const [balanceError, setBalanceError] = useState('');
|
|
28
|
+
|
|
29
|
+
const { data: balance, isSuccess: isBalanceSuccess } = useCurrencyBalance({
|
|
30
|
+
currencyAddress,
|
|
31
|
+
chainId,
|
|
32
|
+
userAddress,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!checkBalance?.enabled) {
|
|
37
|
+
setBalanceError('');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const priceAmountRaw = price$.amountRaw.get() || '0';
|
|
42
|
+
const hasInsufficientBalance =
|
|
43
|
+
isBalanceSuccess &&
|
|
44
|
+
priceAmountRaw &&
|
|
45
|
+
currencyDecimals &&
|
|
46
|
+
BigInt(priceAmountRaw) > (balance?.value || 0n);
|
|
47
|
+
|
|
48
|
+
if (hasInsufficientBalance) {
|
|
49
|
+
setBalanceError('Insufficient balance');
|
|
50
|
+
checkBalance.callback(true);
|
|
51
|
+
} else {
|
|
52
|
+
setBalanceError('');
|
|
53
|
+
checkBalance.callback(false);
|
|
54
|
+
}
|
|
55
|
+
}, [
|
|
56
|
+
price$.amountRaw.get(),
|
|
57
|
+
currencyAddress,
|
|
58
|
+
balance?.value,
|
|
59
|
+
isBalanceSuccess,
|
|
60
|
+
checkBalance,
|
|
61
|
+
currencyDecimals,
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
balanceError,
|
|
66
|
+
};
|
|
67
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type Observable } from '@legendapp/state';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { parseUnits } from 'viem';
|
|
4
|
+
import type { Price } from '../../../../../../../types';
|
|
5
|
+
|
|
6
|
+
type UsePriceInputProps = {
|
|
7
|
+
price$: Observable<Price | undefined>;
|
|
8
|
+
currencyDecimals: number;
|
|
9
|
+
onPriceChange?: () => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const usePriceInput = ({
|
|
13
|
+
price$,
|
|
14
|
+
currencyDecimals,
|
|
15
|
+
onPriceChange,
|
|
16
|
+
}: UsePriceInputProps) => {
|
|
17
|
+
const [value, setValue] = useState('');
|
|
18
|
+
|
|
19
|
+
// Update price amount when currency changes to trigger balance check
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const currentAmount = value.replace(/,/g, '');
|
|
22
|
+
if (currentAmount) {
|
|
23
|
+
try {
|
|
24
|
+
const parsedAmount = parseUnits(
|
|
25
|
+
currentAmount,
|
|
26
|
+
Number(currencyDecimals),
|
|
27
|
+
);
|
|
28
|
+
price$.amountRaw.set(parsedAmount.toString());
|
|
29
|
+
} catch {
|
|
30
|
+
price$.amountRaw.set('0');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, [currencyDecimals, value, price$]);
|
|
34
|
+
|
|
35
|
+
const handlePriceChange = (newValue: string) => {
|
|
36
|
+
setValue(newValue);
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const parsedAmount = parseUnits(newValue, Number(currencyDecimals));
|
|
40
|
+
price$.amountRaw.set(parsedAmount.toString());
|
|
41
|
+
|
|
42
|
+
if (onPriceChange && parsedAmount !== 0n) {
|
|
43
|
+
onPriceChange();
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
price$.amountRaw.set('0');
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
value,
|
|
52
|
+
handlePriceChange,
|
|
53
|
+
};
|
|
54
|
+
};
|