@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.
Files changed (115) hide show
  1. package/dist/{chunk-ZWIRTV7A.js → chunk-4VS5NKDD.js} +2 -2
  2. package/dist/{chunk-GSDUAHL3.js → chunk-6WB4GCCJ.js} +1 -1
  3. package/dist/chunk-6WB4GCCJ.js.map +1 -0
  4. package/dist/{chunk-MTFS5SED.js → chunk-6XUCLBZC.js} +3093 -2463
  5. package/dist/chunk-6XUCLBZC.js.map +1 -0
  6. package/dist/{chunk-T5T6JNB2.js → chunk-ATDCYXXV.js} +49 -49
  7. package/dist/chunk-ATDCYXXV.js.map +1 -0
  8. package/dist/{chunk-LSMQVX77.js → chunk-CP2IVRMX.js} +2 -2
  9. package/dist/{chunk-OPMDGQFB.js → chunk-DNDPYQKV.js} +20 -2
  10. package/dist/chunk-DNDPYQKV.js.map +1 -0
  11. package/dist/{chunk-WBJKZOQ7.js → chunk-GLOIEUWC.js} +225 -364
  12. package/dist/chunk-GLOIEUWC.js.map +1 -0
  13. package/dist/{chunk-4RKM3VUV.js → chunk-IQXJZBMR.js} +2 -2
  14. package/dist/{chunk-MQ5WSFDH.js → chunk-J4TRSLTB.js} +29 -4
  15. package/dist/chunk-J4TRSLTB.js.map +1 -0
  16. package/dist/chunk-LHN6EBLM.js +420 -0
  17. package/dist/chunk-LHN6EBLM.js.map +1 -0
  18. package/dist/{chunk-WQCWBXBM.js → chunk-PAZ4MQXZ.js} +1 -1
  19. package/dist/chunk-PAZ4MQXZ.js.map +1 -0
  20. package/dist/{chunk-S5IPE7TH.js → chunk-URX7ZHX4.js} +2 -2
  21. package/dist/chunk-Y75XGZOB.js +11 -0
  22. package/dist/chunk-Y75XGZOB.js.map +1 -0
  23. package/dist/{chunk-Q2BVDQ3G.js → chunk-ZEKRTFBU.js} +1 -1
  24. package/dist/{chunk-Q2BVDQ3G.js.map → chunk-ZEKRTFBU.js.map} +1 -1
  25. package/dist/index.d.ts +3 -2
  26. package/dist/index.js +10 -8
  27. package/dist/index.js.map +1 -1
  28. package/dist/react/_internal/api/index.js +2 -2
  29. package/dist/react/_internal/index.d.ts +1 -1
  30. package/dist/react/_internal/index.js +4 -4
  31. package/dist/react/_internal/wagmi/index.js +2 -2
  32. package/dist/react/hooks/index.d.ts +54 -42
  33. package/dist/react/hooks/index.js +8 -6
  34. package/dist/react/index.css +24 -24
  35. package/dist/react/index.css.map +1 -1
  36. package/dist/react/index.d.ts +2 -2
  37. package/dist/react/index.js +11 -9
  38. package/dist/react/ssr/index.js.map +1 -1
  39. package/dist/react/ui/components/index.css +24 -24
  40. package/dist/react/ui/components/index.css.map +1 -1
  41. package/dist/react/ui/components/index.d.ts +1 -1
  42. package/dist/react/ui/components/index.js +11 -9
  43. package/dist/react/ui/icons/index.js +1 -1
  44. package/dist/react/ui/index.css +24 -24
  45. package/dist/react/ui/index.css.map +1 -1
  46. package/dist/react/ui/index.d.ts +5 -2
  47. package/dist/react/ui/index.js +11 -9
  48. package/dist/react/ui/modals/_internal/components/actionModal/index.css +46 -0
  49. package/dist/react/ui/modals/_internal/components/actionModal/index.css.map +1 -1
  50. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +1 -1
  51. package/dist/react/ui/modals/_internal/components/actionModal/index.js +11 -6
  52. package/dist/types/index.js +4 -4
  53. package/dist/{types-BlDoGvJV.d.ts → types-DZb7GsfL.d.ts} +10 -1
  54. package/dist/utils/index.d.ts +1 -1
  55. package/dist/utils/index.js +2 -2
  56. package/package.json +1 -1
  57. package/src/consts.ts +3 -0
  58. package/src/react/_internal/transaction-machine/useTransactionMachine.ts +9 -12
  59. package/src/react/_internal/transaction-machine/useWallet.ts +58 -0
  60. package/src/react/_internal/transaction-machine/wallet.ts +60 -3
  61. package/src/react/_internal/types.ts +11 -0
  62. package/src/react/hooks/useCancelOrder.tsx +26 -30
  63. package/src/react/hooks/useCancelTransactionSteps.tsx +222 -0
  64. package/src/react/hooks/useGetReceiptFromHash.tsx +32 -0
  65. package/src/react/ui/modals/BuyModal/Modal.tsx +97 -0
  66. package/src/react/ui/modals/BuyModal/hooks/useBuyCollectable.ts +109 -0
  67. package/src/react/ui/modals/BuyModal/hooks/useCheckoutOptions.ts +50 -0
  68. package/src/react/ui/modals/BuyModal/hooks/useFees.ts +38 -0
  69. package/src/react/ui/modals/BuyModal/hooks/useLoadData.ts +58 -0
  70. package/src/react/ui/modals/BuyModal/index.tsx +3 -210
  71. package/src/react/ui/modals/BuyModal/modals/CheckoutModal.tsx +29 -0
  72. package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +84 -0
  73. package/src/react/ui/modals/CreateListingModal/Modal.tsx +150 -207
  74. package/src/react/ui/modals/CreateListingModal/hooks/useCreateListing.tsx +62 -0
  75. package/src/react/ui/modals/CreateListingModal/hooks/useGetTokenApproval.ts +75 -0
  76. package/src/react/ui/modals/CreateListingModal/hooks/useTransactionSteps.tsx +216 -0
  77. package/src/react/ui/modals/CreateListingModal/index.tsx +1 -1
  78. package/src/react/ui/modals/CreateListingModal/store.ts +17 -9
  79. package/src/react/ui/modals/MakeOfferModal/Modal.tsx +173 -215
  80. package/src/react/ui/modals/MakeOfferModal/hooks/useGetTokenApproval.tsx +76 -0
  81. package/src/react/ui/modals/MakeOfferModal/hooks/useMakeOffer.tsx +62 -0
  82. package/src/react/ui/modals/MakeOfferModal/hooks/useTransactionSteps.tsx +225 -0
  83. package/src/react/ui/modals/MakeOfferModal/store.ts +15 -2
  84. package/src/react/ui/modals/SellModal/Modal.tsx +117 -190
  85. package/src/react/ui/modals/SellModal/hooks/useGetTokenApproval.tsx +73 -0
  86. package/src/react/ui/modals/SellModal/hooks/useSell.tsx +65 -0
  87. package/src/react/ui/modals/SellModal/hooks/useTransactionSteps.tsx +224 -0
  88. package/src/react/ui/modals/SellModal/store.ts +14 -1
  89. package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +26 -1
  90. package/src/react/ui/modals/_internal/components/currencyImage/index.tsx +8 -10
  91. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +9 -1
  92. package/src/react/ui/modals/_internal/components/priceInput/hooks/useBalanceCheck.ts +67 -0
  93. package/src/react/ui/modals/_internal/components/priceInput/hooks/usePriceInput.ts +54 -0
  94. package/src/react/ui/modals/_internal/components/priceInput/index.tsx +49 -62
  95. package/src/react/ui/modals/_internal/components/switchChainModal/index.tsx +9 -4
  96. package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +3 -3
  97. package/src/react/ui/modals/_internal/types.ts +1 -1
  98. package/src/react/ui/modals/modal-provider.tsx +1 -1
  99. package/src/utils/_internal/error/transaction.ts +21 -1
  100. package/tsconfig.tsbuildinfo +1 -1
  101. package/dist/chunk-GSDUAHL3.js.map +0 -1
  102. package/dist/chunk-MQ5WSFDH.js.map +0 -1
  103. package/dist/chunk-MTFS5SED.js.map +0 -1
  104. package/dist/chunk-OPMDGQFB.js.map +0 -1
  105. package/dist/chunk-T5T6JNB2.js.map +0 -1
  106. package/dist/chunk-WBJKZOQ7.js.map +0 -1
  107. package/dist/chunk-WQCWBXBM.js.map +0 -1
  108. package/src/react/hooks/useCreateListing.tsx +0 -125
  109. package/src/react/hooks/useMakeOffer.tsx +0 -122
  110. package/src/react/hooks/useSell.tsx +0 -121
  111. /package/dist/{chunk-ZWIRTV7A.js.map → chunk-4VS5NKDD.js.map} +0 -0
  112. /package/dist/{chunk-LSMQVX77.js.map → chunk-CP2IVRMX.js.map} +0 -0
  113. /package/dist/{chunk-4RKM3VUV.js.map → chunk-IQXJZBMR.js.map} +0 -0
  114. /package/dist/{chunk-S5IPE7TH.js.map → chunk-URX7ZHX4.js.map} +0 -0
  115. /package/src/react/ui/modals/BuyModal/{_store.ts → store.ts} +0 -0
@@ -4,15 +4,17 @@ import {
4
4
  type Chain,
5
5
  type Hex,
6
6
  type TransactionReceipt,
7
- TypedDataDomain,
7
+ type TypedDataDomain,
8
8
  type WalletClient as ViemWalletClient,
9
9
  custom,
10
+ erc20Abi,
11
+ erc721Abi,
10
12
  hexToBigInt,
11
13
  isHex,
12
14
  } from 'viem';
13
15
  import type { Connector } from 'wagmi';
14
16
  import type { SwitchChainErrorType } from 'wagmi/actions';
15
- import { getPublicRpcClient } from '../../../utils';
17
+ import { ERC1155_ABI, getPublicRpcClient } from '../../../utils';
16
18
  import {
17
19
  ChainSwitchError,
18
20
  TransactionConfirmationError,
@@ -23,6 +25,10 @@ import {
23
25
  import { StepType, WalletKind } from '../api';
24
26
  import { createLogger } from './logger';
25
27
  import type { SignatureStep, TransactionStep } from './utils';
28
+ import {
29
+ SEQUENCE_MARKET_V1_ADDRESS,
30
+ SEQUENCE_MARKET_V2_ADDRESS,
31
+ } from '../../../consts';
26
32
 
27
33
  interface WalletClient extends Omit<ViemWalletClient, 'account'> {
28
34
  account: Account;
@@ -44,6 +50,11 @@ export interface WalletInstance {
44
50
  txHash: Hex,
45
51
  chainId: number,
46
52
  ) => Promise<TransactionReceipt>;
53
+ hasTokenApproval: (args: {
54
+ tokenType: 'ERC20' | 'ERC721' | 'ERC1155';
55
+ contractAddress: Address;
56
+ spender: Address | 'sequenceMarketV1' | 'sequenceMarketV2';
57
+ }) => Promise<bigint | boolean>;
47
58
  }
48
59
 
49
60
  export const wallet = ({
@@ -57,7 +68,7 @@ export const wallet = ({
57
68
  }): WalletInstance => {
58
69
  const logger = createLogger('Wallet');
59
70
 
60
- return {
71
+ const walletInstance = {
61
72
  transport: custom(wallet.transport),
62
73
  isWaaS: connector.id.endsWith('waas'),
63
74
  walletKind:
@@ -176,5 +187,51 @@ export const wallet = ({
176
187
  throw new TransactionConfirmationError(txHash, error as Error);
177
188
  }
178
189
  },
190
+ hasTokenApproval: async ({
191
+ tokenType,
192
+ contractAddress,
193
+ spender,
194
+ }: {
195
+ tokenType: 'ERC20' | 'ERC721' | 'ERC1155';
196
+ contractAddress: Address;
197
+ spender: Address | 'sequenceMarketV1' | 'sequenceMarketV2';
198
+ }) => {
199
+ const publicClient = getPublicRpcClient(await wallet.getChainId());
200
+ const walletAddress = await walletInstance.address();
201
+ const spenderAddress =
202
+ spender === 'sequenceMarketV1'
203
+ ? SEQUENCE_MARKET_V1_ADDRESS
204
+ : spender === 'sequenceMarketV2'
205
+ ? SEQUENCE_MARKET_V2_ADDRESS
206
+ : spender;
207
+
208
+ switch (tokenType) {
209
+ case 'ERC20':
210
+ return await publicClient.readContract({
211
+ address: contractAddress as Hex,
212
+ abi: erc20Abi,
213
+ functionName: 'allowance',
214
+ args: [walletAddress, spenderAddress],
215
+ });
216
+ case 'ERC721':
217
+ return await publicClient.readContract({
218
+ address: contractAddress as Hex,
219
+ abi: erc721Abi,
220
+ functionName: 'isApprovedForAll',
221
+ args: [walletAddress, spenderAddress],
222
+ });
223
+ case 'ERC1155':
224
+ return await publicClient.readContract({
225
+ address: contractAddress as Hex,
226
+ abi: ERC1155_ABI,
227
+ functionName: 'isApprovedForAll',
228
+ args: [walletAddress, spenderAddress],
229
+ });
230
+ default:
231
+ throw new Error('Unsupported contract type for approval checking');
232
+ }
233
+ },
179
234
  };
235
+
236
+ return walletInstance;
180
237
  };
@@ -35,3 +35,14 @@ export const AddressSchema = z.string().transform((val, ctx) => {
35
35
  export type ChainId = z.infer<typeof ChainIdSchema>;
36
36
 
37
37
  export type CollectionType = ContractType.ERC1155 | ContractType.ERC721;
38
+
39
+ type TransactionStep = {
40
+ exist: boolean;
41
+ isExecuting: boolean;
42
+ execute: () => Promise<void>;
43
+ };
44
+
45
+ export type TransactionSteps = {
46
+ approval: TransactionStep;
47
+ transaction: TransactionStep;
48
+ };
@@ -1,45 +1,41 @@
1
- import type { Hex } from 'viem';
2
- import {
3
- type CancelInput,
4
- TransactionType,
5
- } from '../_internal/transaction-machine/execute-transaction';
6
- import {
7
- type UseTransactionMachineConfig,
8
- useTransactionMachine,
9
- } from '../_internal/transaction-machine/useTransactionMachine';
1
+ import { useState } from 'react';
2
+ import { useCancelTransactionSteps } from './useCancelTransactionSteps';
10
3
 
11
- interface UseCancelOrderArgs
12
- extends Omit<UseTransactionMachineConfig, 'type' | 'orderbookKind'> {
13
- onSuccess?: (hash: string) => void;
4
+ interface UseCancelOrderArgs {
5
+ collectionAddress: string;
6
+ chainId: string;
7
+ onSuccess?: ({ hash, orderId }: { hash?: string; orderId?: string }) => void;
14
8
  onError?: (error: Error) => void;
15
- onTransactionSent?: (hash?: Hex) => void;
16
- enabled: boolean;
17
9
  }
18
10
 
11
+ export type TransactionStep = {
12
+ exist: boolean;
13
+ isExecuting: boolean;
14
+ execute: () => Promise<void>;
15
+ };
16
+
19
17
  export const useCancelOrder = ({
18
+ collectionAddress,
19
+ chainId,
20
20
  onSuccess,
21
21
  onError,
22
- onTransactionSent,
23
- enabled,
24
- ...config
25
22
  }: UseCancelOrderArgs) => {
26
- const machineConfig = {
27
- ...config,
28
- type: TransactionType.CANCEL,
29
- };
30
- const { machine, isLoading } = useTransactionMachine({
31
- config: machineConfig,
32
- enabled,
23
+ const [steps, setSteps] = useState<TransactionStep>({
24
+ exist: false,
25
+ isExecuting: false,
26
+ execute: () => Promise.resolve(),
27
+ });
28
+
29
+ const { cancelOrder } = useCancelTransactionSteps({
30
+ collectionAddress,
31
+ chainId,
33
32
  onSuccess,
34
33
  onError,
35
- onTransactionSent,
34
+ setSteps,
36
35
  });
37
36
 
38
37
  return {
39
- cancel: (props: CancelInput) => machine?.start(props),
40
- onError,
41
- onSuccess,
42
- onTransactionSent,
43
- isLoading,
38
+ cancelOrder,
39
+ isExecuting: steps.isExecuting,
44
40
  };
45
41
  };
@@ -0,0 +1,222 @@
1
+ import {
2
+ ExecuteType,
3
+ getMarketplaceClient,
4
+ MarketplaceKind,
5
+ Step,
6
+ StepType,
7
+ } from '../_internal';
8
+ import { useWallet } from '../_internal/transaction-machine/useWallet';
9
+ import { ModalCallbacks } from '../ui/modals/_internal/types';
10
+ import { useConfig } from './useConfig';
11
+ import { useGenerateCancelTransaction } from './useGenerateCancelTransaction';
12
+ import { TransactionStep } from './useCancelOrder';
13
+ import { SignatureStep } from '../_internal/transaction-machine/utils';
14
+ import { useGetReceiptFromHash } from './useGetReceiptFromHash';
15
+ import { Hex } from 'viem';
16
+ import { useSwitchChainModal } from '../ui/modals/_internal/components/switchChainModal';
17
+ import {
18
+ ChainSwitchUserRejectedError,
19
+ WalletInstanceNotFoundError,
20
+ } from '../../utils/_internal/error/transaction';
21
+
22
+ interface UseCancelTransactionStepsArgs {
23
+ collectionAddress: string;
24
+ chainId: string;
25
+ callbacks?: ModalCallbacks;
26
+ setSteps: React.Dispatch<React.SetStateAction<TransactionStep>>;
27
+ onSuccess?: ({ hash, orderId }: { hash?: string; orderId?: string }) => void;
28
+ onError?: (error: Error) => void;
29
+ }
30
+
31
+ export const useCancelTransactionSteps = ({
32
+ collectionAddress,
33
+ chainId,
34
+ callbacks,
35
+ setSteps,
36
+ onSuccess,
37
+ onError,
38
+ }: UseCancelTransactionStepsArgs) => {
39
+ const { show: showSwitchChainModal } = useSwitchChainModal();
40
+ const { wallet, isLoading, isError } = useWallet();
41
+ const walletIsInitialized = wallet && !isLoading && !isError;
42
+ const sdkConfig = useConfig();
43
+ const marketplaceClient = getMarketplaceClient(chainId, sdkConfig);
44
+ const { waitForReceipt } = useGetReceiptFromHash();
45
+ const { generateCancelTransactionAsync } = useGenerateCancelTransaction({
46
+ chainId,
47
+ });
48
+
49
+ const getWalletChainId = async () => {
50
+ return await wallet!.getChainId();
51
+ };
52
+ const switchChain = async () => {
53
+ await wallet!.switchChain(Number(chainId));
54
+ };
55
+ const checkAndSwitchChain = async () => {
56
+ const walletChainId = await getWalletChainId();
57
+ const isWaaS = wallet?.isWaaS;
58
+ const chainIdMismatch = walletChainId !== Number(chainId);
59
+
60
+ return new Promise((resolve, reject) => {
61
+ if (chainIdMismatch) {
62
+ if (isWaaS) {
63
+ switchChain().then(resolve).catch(reject);
64
+ } else {
65
+ showSwitchChainModal({
66
+ chainIdToSwitchTo: chainId,
67
+ onSuccess: () => resolve({ chainId: chainId }),
68
+ onError: (error) => reject(error),
69
+ onClose: () => reject(new ChainSwitchUserRejectedError()),
70
+ });
71
+ }
72
+ } else {
73
+ resolve({ chainId: chainId });
74
+ }
75
+ });
76
+ };
77
+
78
+ const getCancelSteps = async ({
79
+ orderId,
80
+ marketplace,
81
+ }: {
82
+ orderId: string;
83
+ marketplace: MarketplaceKind;
84
+ }) => {
85
+ try {
86
+ const address = await wallet!.address();
87
+
88
+ const steps = await generateCancelTransactionAsync({
89
+ collectionAddress,
90
+ maker: address,
91
+ marketplace,
92
+ orderId,
93
+ });
94
+
95
+ return steps;
96
+ } catch (error) {
97
+ if (callbacks?.onError) {
98
+ callbacks.onError(error as Error);
99
+ } else {
100
+ console.debug('onError callback not provided:', error);
101
+ }
102
+ throw error;
103
+ }
104
+ };
105
+
106
+ const cancelOrder = async ({
107
+ orderId,
108
+ marketplace,
109
+ }: {
110
+ orderId: string;
111
+ marketplace: MarketplaceKind;
112
+ }) => {
113
+ if (!walletIsInitialized) {
114
+ throw new WalletInstanceNotFoundError();
115
+ }
116
+
117
+ try {
118
+ await checkAndSwitchChain();
119
+
120
+ setSteps((prev) => ({
121
+ ...prev,
122
+ isExecuting: true,
123
+ }));
124
+
125
+ const cancelSteps = await getCancelSteps({
126
+ orderId,
127
+ marketplace,
128
+ });
129
+ const transactionStep = cancelSteps?.find(
130
+ (step) => step.id === StepType.cancel,
131
+ );
132
+ const signatureStep = cancelSteps?.find(
133
+ (step) => step.id === StepType.signEIP712,
134
+ );
135
+
136
+ console.debug('transactionStep', transactionStep);
137
+ console.debug('signatureStep', signatureStep);
138
+
139
+ if (!transactionStep && !signatureStep) {
140
+ throw new Error('No transaction or signature step found');
141
+ }
142
+
143
+ let hash: Hex | undefined, reservoirOrderId: string | undefined;
144
+
145
+ if (transactionStep && wallet) {
146
+ hash = await executeTransaction({ transactionStep });
147
+
148
+ if (hash) {
149
+ await waitForReceipt(hash);
150
+
151
+ if (onSuccess && typeof onSuccess === 'function') {
152
+ onSuccess({ hash });
153
+ }
154
+
155
+ setSteps((prev) => ({
156
+ ...prev,
157
+ isExecuting: false,
158
+ }));
159
+ }
160
+ }
161
+
162
+ if (signatureStep) {
163
+ reservoirOrderId = await executeSignature({ signatureStep });
164
+
165
+ if (onSuccess && typeof onSuccess === 'function') {
166
+ onSuccess({ orderId: reservoirOrderId });
167
+ }
168
+
169
+ setSteps((prev) => ({
170
+ ...prev,
171
+ isExecuting: false,
172
+ }));
173
+ }
174
+ } catch (error) {
175
+ setSteps((prev) => ({
176
+ ...prev,
177
+ isExecuting: false,
178
+ }));
179
+
180
+ if (onError && typeof onError === 'function') {
181
+ onError(error as Error);
182
+ }
183
+
184
+ throw error;
185
+ }
186
+ };
187
+
188
+ const executeTransaction = async ({
189
+ transactionStep,
190
+ }: {
191
+ transactionStep: Step;
192
+ }): Promise<Hex | undefined> => {
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
+ }: {
204
+ signatureStep: Step;
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
+ cancelOrder,
221
+ };
222
+ };
@@ -0,0 +1,32 @@
1
+ import { Hex } from 'viem';
2
+ import { usePublicClient } from 'wagmi';
3
+ import { useCallback } from 'react';
4
+
5
+ /**
6
+ * @returns a function to wait for a transaction receipt and the receipt
7
+ * @description This hook is used to wait for a transaction receipt and the receipt
8
+ * @example
9
+ * const { waitForReceipt } = useGetReceiptFromHash();
10
+ * const receipt = await waitForReceipt(transactionHash);
11
+ */
12
+ export const useGetReceiptFromHash = () => {
13
+ const publicClient = usePublicClient();
14
+
15
+ const waitForReceipt = useCallback(
16
+ async (transactionHash: Hex) => {
17
+ if (!publicClient) {
18
+ throw new Error('Public client not found');
19
+ }
20
+
21
+ const receipt = await publicClient.waitForTransactionReceipt({
22
+ hash: transactionHash,
23
+ });
24
+ return receipt;
25
+ },
26
+ [publicClient],
27
+ );
28
+
29
+ return {
30
+ waitForReceipt,
31
+ };
32
+ };
@@ -0,0 +1,97 @@
1
+ import { use$ } from '@legendapp/state/react';
2
+ import type { Hex } from 'viem';
3
+ import { ContractType, TokenMetadata } from '../../../_internal';
4
+ import { buyModal$ } from './store';
5
+ import { LoadingModal } from '../_internal/components/actionModal/LoadingModal';
6
+ import { CheckoutModal } from './modals/CheckoutModal';
7
+ import { ERC1155QuantityModal } from './modals/Modal1155';
8
+ import { useLoadData } from './hooks/useLoadData';
9
+ import { useBuyCollectable } from './hooks/useBuyCollectable';
10
+ import { ErrorModal } from '../_internal/components/actionModal/ErrorModal';
11
+
12
+ export const BuyModal = () => {
13
+ const isOpen = use$(buyModal$.isOpen);
14
+
15
+ if (!isOpen) return null;
16
+
17
+ return <BuyModalContent />;
18
+ };
19
+
20
+ const BuyModalContent = () => {
21
+ const chainId = String(use$(buyModal$.state.order.chainId));
22
+ const collectionAddress = use$(
23
+ buyModal$.state.order.collectionContractAddress,
24
+ ) as Hex;
25
+ const collectibleId = use$(buyModal$.state.order.tokenId);
26
+ const modalId = use$(buyModal$.state.modalId);
27
+ const callbacks = use$(buyModal$.callbacks);
28
+ const order = use$(buyModal$.state.order);
29
+ const isOpen = use$(buyModal$.isOpen);
30
+
31
+ const { collection, collectable, checkoutOptions, isLoading, isError } =
32
+ useLoadData({
33
+ chainId: Number(chainId),
34
+ collectionAddress,
35
+ collectibleId,
36
+ orderId: order.orderId,
37
+ marketplace: order.marketplace,
38
+ });
39
+
40
+ const {
41
+ buy,
42
+ isLoading: buyIsLoading,
43
+ isError: buyIsError,
44
+ } = useBuyCollectable({
45
+ chainId,
46
+ collectionAddress,
47
+ callbacks,
48
+ tokenId: collectibleId,
49
+ priceCurrencyAddress: order.priceCurrencyAddress,
50
+ });
51
+
52
+ if (
53
+ isLoading ||
54
+ !collection ||
55
+ !collectable ||
56
+ !checkoutOptions ||
57
+ buyIsLoading
58
+ ) {
59
+ return (
60
+ <LoadingModal
61
+ isOpen={isOpen}
62
+ chainId={Number(chainId)}
63
+ onClose={buyModal$.close}
64
+ title="Loading Sequence Pay"
65
+ />
66
+ );
67
+ }
68
+
69
+ if (buyIsError || isError) {
70
+ return (
71
+ <ErrorModal
72
+ isOpen={isOpen}
73
+ chainId={Number(chainId)}
74
+ onClose={buyModal$.close}
75
+ title="Error"
76
+ />
77
+ );
78
+ }
79
+
80
+ return collection.type === ContractType.ERC721 ? (
81
+ <CheckoutModal
82
+ key={modalId}
83
+ buy={(input) => buy({ ...input, checkoutOptions })}
84
+ collectable={collectable as TokenMetadata}
85
+ order={order}
86
+ />
87
+ ) : (
88
+ <ERC1155QuantityModal
89
+ buy={(input) => buy({ ...input, checkoutOptions })}
90
+ collectable={collectable as TokenMetadata}
91
+ order={order}
92
+ chainId={chainId}
93
+ collectionAddress={collectionAddress}
94
+ collectibleId={collectibleId}
95
+ />
96
+ );
97
+ };
@@ -0,0 +1,109 @@
1
+ import { useSelectPaymentModal } from '@0xsequence/kit-checkout';
2
+ import type { Hash, Hex } from 'viem';
3
+ import type { ModalCallbacks } from '../../_internal/types';
4
+ import {
5
+ type CheckoutOptions,
6
+ getMarketplaceClient,
7
+ type MarketplaceKind,
8
+ WalletKind,
9
+ } from '../../../../_internal';
10
+ import { buyModal$ } from '../store';
11
+ import { useFees } from './useFees';
12
+ import { useConfig } from '../../../../hooks';
13
+ import { useWallet } from '../../../../_internal/transaction-machine/useWallet';
14
+
15
+ interface UseBuyCollectableProps {
16
+ chainId: string;
17
+ collectionAddress: string;
18
+ tokenId: string;
19
+ callbacks?: ModalCallbacks;
20
+ priceCurrencyAddress: string;
21
+ }
22
+
23
+ type BuyCollectableReturn =
24
+ | { status: 'loading'; buy: null; isLoading: true; isError: false }
25
+ | { status: 'error'; buy: null; isLoading: false; isError: true }
26
+ | {
27
+ status: 'ready';
28
+ isLoading: false;
29
+ isError: false;
30
+ buy: (input: {
31
+ orderId: string;
32
+ quantity: string;
33
+ collectableDecimals: number;
34
+ marketplace: MarketplaceKind;
35
+ checkoutOptions: CheckoutOptions;
36
+ }) => Promise<void>;
37
+ };
38
+
39
+ export const useBuyCollectable = ({
40
+ chainId,
41
+ collectionAddress,
42
+ tokenId,
43
+ callbacks,
44
+ priceCurrencyAddress,
45
+ }: UseBuyCollectableProps): BuyCollectableReturn => {
46
+ const { openSelectPaymentModal } = useSelectPaymentModal();
47
+ const config = useConfig();
48
+ const marketplaceClient = getMarketplaceClient(Number(chainId), config);
49
+ const fees = useFees({ chainId: Number(chainId), collectionAddress });
50
+ const { wallet, isLoading, isError } = useWallet();
51
+
52
+ if (isLoading) {
53
+ return { status: 'loading', buy: null, isLoading, isError: false };
54
+ }
55
+
56
+ if (isError || !wallet) {
57
+ return { status: 'error', buy: null, isLoading, isError: true };
58
+ }
59
+
60
+ return {
61
+ status: 'ready',
62
+ isLoading,
63
+ isError,
64
+ buy: async (input) => {
65
+ const { steps } = await marketplaceClient.generateBuyTransaction({
66
+ collectionAddress,
67
+ buyer: await wallet.address(),
68
+ marketplace: input.marketplace,
69
+ ordersData: [
70
+ {
71
+ orderId: input.orderId,
72
+ quantity: input.quantity,
73
+ },
74
+ ],
75
+ additionalFees: [fees],
76
+ walletType: WalletKind.unknown,
77
+ });
78
+
79
+ const step = steps[0];
80
+
81
+ openSelectPaymentModal({
82
+ chain: chainId,
83
+ collectibles: [
84
+ {
85
+ tokenId: tokenId,
86
+ quantity: input.quantity,
87
+ decimals: input.collectableDecimals,
88
+ },
89
+ ],
90
+ currencyAddress: priceCurrencyAddress,
91
+ price: step.value,
92
+ targetContractAddress: step.to,
93
+ txData: step.data as Hex,
94
+ collectionAddress,
95
+ recipientAddress: await wallet.address(),
96
+ enableMainCurrencyPayment: true,
97
+ enableSwapPayments: !!input.checkoutOptions.swap,
98
+ creditCardProviders: input.checkoutOptions.nftCheckout || [],
99
+ onSuccess: (hash: string) =>
100
+ callbacks?.onSuccess?.({ hash: hash as Hash }),
101
+ onError: callbacks?.onError,
102
+ onClose: () => {
103
+ console.log('onClose');
104
+ buyModal$.close();
105
+ },
106
+ });
107
+ },
108
+ };
109
+ };
@@ -0,0 +1,50 @@
1
+ import type { Hex } from 'viem';
2
+ import {
3
+ getMarketplaceClient,
4
+ type MarketplaceKind,
5
+ } from '../../../../_internal';
6
+ import { useConfig } from '../../../../hooks';
7
+ import { useWallet } from '../../../../_internal/transaction-machine/useWallet';
8
+ import { useFees } from './useFees';
9
+ import { useQuery } from '@tanstack/react-query';
10
+
11
+ export const useCheckoutOptions = (input: {
12
+ chainId: number;
13
+ collectionAddress: Hex;
14
+ orderId: string;
15
+ marketplace: MarketplaceKind;
16
+ }) => {
17
+ const config = useConfig();
18
+ const { wallet } = useWallet();
19
+ const fees = useFees({
20
+ chainId: input.chainId,
21
+ collectionAddress: input.collectionAddress,
22
+ });
23
+
24
+ return useQuery({
25
+ queryKey: [
26
+ 'checkoutOptions',
27
+ input.chainId,
28
+ input.collectionAddress,
29
+ input.orderId,
30
+ input.marketplace,
31
+ ],
32
+ queryFn: async () => {
33
+ const marketplaceClient = getMarketplaceClient(input.chainId, config);
34
+ return marketplaceClient
35
+ .checkoutOptionsMarketplace({
36
+ wallet: await wallet!.address(),
37
+ orders: [
38
+ {
39
+ contractAddress: input.collectionAddress,
40
+ orderId: input.orderId,
41
+ marketplace: input.marketplace,
42
+ },
43
+ ],
44
+ additionalFee: Number(fees.amount),
45
+ })
46
+ .then((res) => res.options);
47
+ },
48
+ enabled: !!wallet,
49
+ });
50
+ };