@0xsequence/marketplace-sdk 0.5.2 → 0.5.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 (184) hide show
  1. package/dist/builder-types-Jl3Ymws8.d.ts +73 -0
  2. package/dist/{chunk-XP3WY5AX.js → chunk-7C7ADZ2H.js} +3 -3
  3. package/dist/{chunk-XP3WY5AX.js.map → chunk-7C7ADZ2H.js.map} +1 -1
  4. package/dist/{chunk-FCF57DZI.js → chunk-7FN62HOP.js} +5 -9
  5. package/dist/chunk-7FN62HOP.js.map +1 -0
  6. package/dist/chunk-DZKPDV63.js +27 -0
  7. package/dist/chunk-DZKPDV63.js.map +1 -0
  8. package/dist/{chunk-ZUEQGPLO.js → chunk-J6F5QOW5.js} +2 -2
  9. package/dist/{chunk-ZUEQGPLO.js.map → chunk-J6F5QOW5.js.map} +1 -1
  10. package/dist/{chunk-I37CRQ4S.js → chunk-JWNONWD6.js} +259 -173
  11. package/dist/chunk-JWNONWD6.js.map +1 -0
  12. package/dist/{chunk-LJAB3S6U.js → chunk-TFRAOS7F.js} +22 -13
  13. package/dist/chunk-TFRAOS7F.js.map +1 -0
  14. package/dist/{chunk-MKGSGTQC.js → chunk-TLNRD4BQ.js} +3 -3
  15. package/dist/{chunk-5NORRVPM.js → chunk-UZIAX32Y.js} +1 -1
  16. package/dist/{chunk-5NORRVPM.js.map → chunk-UZIAX32Y.js.map} +1 -1
  17. package/dist/chunk-WGGZEQHL.js +56 -0
  18. package/dist/chunk-WGGZEQHL.js.map +1 -0
  19. package/dist/{chunk-MWDG7UTB.js → chunk-ZBLU3Q22.js} +1 -1
  20. package/dist/{chunk-MSTTVFVQ.js → chunk-ZGVCOQ4I.js} +383 -283
  21. package/dist/chunk-ZGVCOQ4I.js.map +1 -0
  22. package/dist/{create-config-BXvwUh55.d.ts → create-config-DOUq8Day.d.ts} +2 -2
  23. package/dist/index.css +1 -1
  24. package/dist/index.d.ts +5 -4
  25. package/dist/index.js +10 -6
  26. package/dist/{sdk-config-B32_2bG3.d.ts → marketplace.gen-D0ADxbfH.d.ts} +1 -24
  27. package/dist/react/_internal/api/index.d.ts +3 -2
  28. package/dist/react/_internal/databeat/index.css +82 -0
  29. package/dist/react/_internal/databeat/index.css.map +1 -0
  30. package/dist/react/_internal/databeat/index.d.ts +68 -0
  31. package/dist/react/_internal/databeat/index.js +26 -0
  32. package/dist/react/_internal/databeat/index.js.map +1 -0
  33. package/dist/react/_internal/index.d.ts +6 -5
  34. package/dist/react/_internal/index.js +6 -6
  35. package/dist/react/_internal/wagmi/index.d.ts +4 -4
  36. package/dist/react/_internal/wagmi/index.js +1 -1
  37. package/dist/react/hooks/index.d.ts +367 -22
  38. package/dist/react/hooks/index.js +9 -7
  39. package/dist/react/index.css +1 -1
  40. package/dist/react/index.css.map +1 -1
  41. package/dist/react/index.d.ts +7 -6
  42. package/dist/react/index.js +15 -12
  43. package/dist/react/ssr/index.d.ts +54 -41
  44. package/dist/react/ssr/index.js +5 -9
  45. package/dist/react/ssr/index.js.map +1 -1
  46. package/dist/react/ui/components/collectible-card/index.css +1 -1
  47. package/dist/react/ui/components/collectible-card/index.css.map +1 -1
  48. package/dist/react/ui/components/collectible-card/index.d.ts +4 -3
  49. package/dist/react/ui/components/collectible-card/index.js +9 -8
  50. package/dist/react/ui/components/marketplace-logos/index.js +1 -1
  51. package/dist/react/ui/index.css +1 -1
  52. package/dist/react/ui/index.css.map +1 -1
  53. package/dist/react/ui/index.d.ts +4 -3
  54. package/dist/react/ui/index.js +9 -8
  55. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +4 -3
  56. package/dist/react/ui/modals/_internal/components/actionModal/index.js +6 -6
  57. package/dist/react/ui/styles/index.d.ts +1 -1
  58. package/dist/sdk-config-xWkdBdrL.d.ts +24 -0
  59. package/dist/{services-BRBVE0mm.d.ts → services-Dd2MoBTM.d.ts} +2 -1
  60. package/dist/styles/index.css +1 -1
  61. package/dist/styles/index.css.map +1 -1
  62. package/dist/styles/index.d.ts +1 -1
  63. package/dist/styles/index.js +1 -1
  64. package/dist/types/index.d.ts +4 -5
  65. package/dist/types/index.js +9 -5
  66. package/dist/{types-Yto6KrTN.d.ts → types-vOfhbBkR.d.ts} +3 -2
  67. package/dist/utils/index.d.ts +4 -3
  68. package/dist/utils/index.js +4 -4
  69. package/package.json +12 -10
  70. package/src/react/_internal/api/__mocks__/indexer.msw.ts +197 -0
  71. package/src/react/_internal/api/__mocks__/marketplace.msw.ts +140 -1
  72. package/src/react/_internal/api/__mocks__/metadata.msw.ts +162 -0
  73. package/src/react/_internal/databeat/index.ts +63 -0
  74. package/src/react/_internal/databeat/types.ts +70 -0
  75. package/src/react/_internal/test/mocks/publicClient.ts +39 -0
  76. package/src/react/_internal/test/mocks/wagmi.ts +61 -0
  77. package/src/react/_internal/test/mocks/wallet.ts +61 -0
  78. package/src/react/_internal/test/setup.ts +28 -0
  79. package/src/react/_internal/test-utils.tsx +31 -2
  80. package/src/react/_internal/wagmi/__tests__/create-config.test.ts +53 -20
  81. package/src/react/_internal/wagmi/create-config.ts +3 -4
  82. package/src/react/_internal/wagmi/embedded.ts +1 -4
  83. package/src/react/_internal/wagmi/universal.ts +1 -4
  84. package/src/react/_internal/wallet/wallet.ts +1 -0
  85. package/src/react/hooks/__tests__/useAutoSelectFeeOption.test.tsx +314 -0
  86. package/src/react/hooks/__tests__/useBalanceOfCollectible.test.tsx +148 -0
  87. package/src/react/hooks/__tests__/useCancelOrder.test.tsx +410 -0
  88. package/src/react/hooks/__tests__/useCancelTransactionSteps.test.tsx +269 -0
  89. package/src/react/hooks/__tests__/useCollectible.test.tsx +120 -0
  90. package/src/react/hooks/__tests__/useCollection.test.tsx +101 -0
  91. package/src/react/hooks/__tests__/useCollectionBalanceDetails.test.tsx +175 -0
  92. package/src/react/hooks/__tests__/useCollectionDetails.test.tsx +82 -0
  93. package/src/react/hooks/__tests__/useCollectionDetailsPolling.test.tsx +133 -0
  94. package/src/react/hooks/__tests__/useCountListingsForCollectible.test.tsx +108 -0
  95. package/src/react/hooks/__tests__/useCountOfCollectables.test.tsx +129 -0
  96. package/src/react/hooks/__tests__/useCountOffersForCollectible.test.tsx +108 -0
  97. package/src/react/hooks/__tests__/useCurrencies.test.tsx +176 -0
  98. package/src/react/hooks/__tests__/useCurrency.test.tsx +153 -0
  99. package/src/react/hooks/__tests__/useCurrencyBalance.test.tsx +111 -0
  100. package/src/react/hooks/__tests__/useFilters.test.tsx +127 -0
  101. package/src/react/hooks/__tests__/useFloorOrder.test.tsx +101 -0
  102. package/src/react/hooks/__tests__/useGenerateBuyTransaction.test.tsx +173 -0
  103. package/src/react/hooks/__tests__/useGenerateCancelTransaction.test.tsx +207 -0
  104. package/src/react/hooks/__tests__/useGenerateListingTransaction.test.tsx +207 -0
  105. package/src/react/hooks/__tests__/useGenerateOfferTransaction.test.tsx +205 -0
  106. package/src/react/hooks/__tests__/useGenerateSellTransaction.test.tsx +181 -0
  107. package/src/react/hooks/__tests__/useHighestOffer.test.tsx +118 -0
  108. package/src/react/hooks/__tests__/useListBalances.test.tsx +136 -0
  109. package/src/react/hooks/__tests__/useListCollectibleActivities.test.tsx +200 -0
  110. package/src/react/hooks/__tests__/useListCollectibles.test.tsx +232 -0
  111. package/src/react/hooks/__tests__/useListCollectiblesPaginated.test.tsx +217 -0
  112. package/src/react/hooks/__tests__/useListCollectionActivities.test.tsx +235 -0
  113. package/src/react/hooks/__tests__/useListCollections.test.tsx +296 -0
  114. package/src/react/hooks/__tests__/useListListingsForCollectible.test.tsx +140 -0
  115. package/src/react/hooks/__tests__/useListOffersForCollectible.test.tsx +140 -0
  116. package/src/react/hooks/__tests__/useLowestListing.test.tsx +148 -0
  117. package/src/react/hooks/__tests__/useMarketplaceConfig.test.tsx +106 -0
  118. package/src/react/hooks/__tests__/useRoyaltyPercentage.test.tsx +129 -0
  119. package/src/react/hooks/index.ts +1 -1
  120. package/src/react/hooks/options/__mocks__/marketplaceConfig.msw.ts +66 -10
  121. package/src/react/hooks/options/__tests__/marketplaceConfigOptions.test.tsx +2 -11
  122. package/src/react/hooks/options/marketplaceConfigOptions.ts +8 -3
  123. package/src/react/hooks/useAutoSelectFeeOption.tsx +4 -3
  124. package/src/react/hooks/useCancelTransactionSteps.tsx +17 -9
  125. package/src/react/hooks/useCollectionDetailsPolling.tsx +1 -1
  126. package/src/react/hooks/useCurrencies.tsx +29 -28
  127. package/src/react/hooks/useFilters.tsx +75 -2
  128. package/src/react/hooks/useGenerateBuyTransaction.tsx +13 -5
  129. package/src/react/hooks/useListCollectibleActivities.tsx +1 -0
  130. package/src/react/hooks/useListCollectibles.tsx +1 -0
  131. package/src/react/hooks/useListCollectiblesPaginated.tsx +78 -0
  132. package/src/react/hooks/useListCollectionActivities.tsx +1 -0
  133. package/src/react/hooks/useListCollections.tsx +2 -2
  134. package/src/react/ui/components/_internals/custom-select/__tests__/CustomSelect.test.tsx +6 -2
  135. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +1 -1
  136. package/src/react/ui/components/collectible-card/Footer.tsx +9 -5
  137. package/src/react/ui/modals/BuyModal/Modal.tsx +9 -4
  138. package/src/react/ui/modals/BuyModal/__tests__/Modal.test.tsx +0 -1
  139. package/src/react/ui/modals/BuyModal/__tests__/store.test.ts +4 -2
  140. package/src/react/ui/modals/BuyModal/hooks/__tests__/useBuyCollectable.test.tsx +1 -24
  141. package/src/react/ui/modals/BuyModal/hooks/__tests__/useCheckoutOptions.test.tsx +152 -210
  142. package/src/react/ui/modals/BuyModal/hooks/__tests__/useFees.test.tsx +19 -49
  143. package/src/react/ui/modals/BuyModal/hooks/useFees.ts +6 -6
  144. package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +4 -2
  145. package/src/react/ui/modals/BuyModal/modals/__tests__/Modal1155.test.tsx +161 -52
  146. package/src/react/ui/modals/BuyModal/store.ts +7 -0
  147. package/src/react/ui/modals/CreateListingModal/Modal.tsx +1 -3
  148. package/src/react/ui/modals/CreateListingModal/__tests__/Modal.test.tsx +59 -227
  149. package/src/react/ui/modals/CreateListingModal/hooks/useCreateListing.tsx +2 -1
  150. package/src/react/ui/modals/CreateListingModal/hooks/useTransactionSteps.tsx +47 -7
  151. package/src/react/ui/modals/MakeOfferModal/Modal.tsx +1 -8
  152. package/src/react/ui/modals/MakeOfferModal/__tests__/Modal.test.tsx +41 -118
  153. package/src/react/ui/modals/MakeOfferModal/hooks/useMakeOffer.tsx +2 -1
  154. package/src/react/ui/modals/MakeOfferModal/hooks/useTransactionSteps.tsx +34 -6
  155. package/src/react/ui/modals/SellModal/Modal.tsx +3 -1
  156. package/src/react/ui/modals/SellModal/__tests__/Modal.test.tsx +4 -3
  157. package/src/react/ui/modals/SellModal/hooks/useGetTokenApproval.tsx +33 -31
  158. package/src/react/ui/modals/SellModal/hooks/useSell.tsx +11 -7
  159. package/src/react/ui/modals/SellModal/hooks/useTransactionSteps.tsx +58 -16
  160. package/src/react/ui/modals/SuccessfulPurchaseModal/__tests__/Modal.test.tsx +0 -1
  161. package/src/react/ui/modals/_internal/components/actionModal/ErrorModal.tsx +4 -2
  162. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +129 -57
  163. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +1 -3
  164. package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +1 -3
  165. package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +2 -2
  166. package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/TransactionStatusModal.test.tsx +8 -8
  167. package/src/react/ui/modals/_internal/components/transactionStatusModal/hooks/useTransactionStatus.ts +1 -0
  168. package/src/types/builder-types.ts +79 -0
  169. package/src/types/index.ts +1 -1
  170. package/src/utils/__tests__/get-public-rpc-client.test.ts +2 -0
  171. package/src/utils/getMarketplaceDetails.ts +2 -2
  172. package/tsconfig.tsbuildinfo +1 -1
  173. package/vitest.config.js +2 -1
  174. package/dist/chunk-FCF57DZI.js.map +0 -1
  175. package/dist/chunk-I37CRQ4S.js.map +0 -1
  176. package/dist/chunk-LJAB3S6U.js.map +0 -1
  177. package/dist/chunk-MSTTVFVQ.js.map +0 -1
  178. package/dist/chunk-RK6KYMZM.js +0 -18
  179. package/dist/chunk-RK6KYMZM.js.map +0 -1
  180. package/dist/marketplace-config-znEu4L0K.d.ts +0 -60
  181. package/src/react/hooks/useCurrencyOptions.tsx +0 -16
  182. package/src/types/marketplace-config.ts +0 -67
  183. /package/dist/{chunk-MKGSGTQC.js.map → chunk-TLNRD4BQ.js.map} +0 -0
  184. /package/dist/{chunk-MWDG7UTB.js.map → chunk-ZBLU3Q22.js.map} +0 -0
@@ -39,7 +39,7 @@ export const useCreateListing = ({
39
39
  useMarketplaceConfig();
40
40
 
41
41
  const collectionConfig = marketplaceConfig?.collections.find(
42
- (c) => c.collectionAddress === collectionAddress,
42
+ (c) => c.address === collectionAddress,
43
43
  );
44
44
 
45
45
  orderbookKind =
@@ -60,6 +60,7 @@ export const useCreateListing = ({
60
60
  },
61
61
  });
62
62
 
63
+ // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
63
64
  useEffect(() => {
64
65
  if (tokenApproval?.step && !tokenApprovalIsLoading) {
65
66
  steps$.approval.exist.set(true);
@@ -1,5 +1,5 @@
1
1
  import type { Observable } from '@legendapp/state';
2
- import type { Address } from 'viem';
2
+ import { type Address, type Hex, formatUnits } from 'viem';
3
3
  import type { OrderbookKind } from '../../../../../types';
4
4
  import {
5
5
  ExecuteType,
@@ -10,14 +10,21 @@ import {
10
10
  collectableKeys,
11
11
  getMarketplaceClient,
12
12
  } from '../../../../_internal';
13
+ import { useAnalytics } from '../../../../_internal/databeat';
13
14
  import { TransactionType } from '../../../../_internal/types';
14
15
  import type { ListingInput } from '../../../../_internal/types';
16
+ import type {
17
+ SignatureStep,
18
+ TransactionStep as WalletTransactionStep,
19
+ } from '../../../../_internal/utils';
15
20
  import { useWallet } from '../../../../_internal/wallet/useWallet';
16
- import type { SignatureStep } from '../../../../_internal/utils';
17
- import { useConfig, useGenerateListingTransaction } from '../../../../hooks';
21
+ import {
22
+ useConfig,
23
+ useCurrencies,
24
+ useGenerateListingTransaction,
25
+ } from '../../../../hooks';
18
26
  import { useTransactionStatusModal } from '../../_internal/components/transactionStatusModal';
19
27
  import type { ModalCallbacks } from '../../_internal/types';
20
-
21
28
  interface UseTransactionStepsArgs {
22
29
  listingInput: ListingInput;
23
30
  chainId: string;
@@ -41,7 +48,11 @@ export const useTransactionSteps = ({
41
48
  const expiry = new Date(Number(listingInput.listing.expiry) * 1000);
42
49
  const { show: showTransactionStatusModal } = useTransactionStatusModal();
43
50
  const sdkConfig = useConfig();
51
+ const { data: currencies } = useCurrencies({
52
+ chainId: Number(chainId),
53
+ });
44
54
  const marketplaceClient = getMarketplaceClient(chainId, sdkConfig);
55
+ const analytics = useAnalytics();
45
56
  const { generateListingTransactionAsync, isPending: generatingSteps } =
46
57
  useGenerateListingTransaction({
47
58
  chainId,
@@ -89,7 +100,7 @@ export const useTransactionSteps = ({
89
100
 
90
101
  const hash = await wallet.handleSendTransactionStep(
91
102
  Number(chainId),
92
- approvalStep as any,
103
+ approvalStep as WalletTransactionStep,
93
104
  );
94
105
 
95
106
  await wallet.handleConfirmTransactionStep(hash, Number(chainId));
@@ -120,7 +131,8 @@ export const useTransactionSteps = ({
120
131
  throw new Error('No transaction or signature step found');
121
132
  }
122
133
 
123
- let hash, orderId: string | undefined;
134
+ let hash: Hex | undefined;
135
+ let orderId: string | undefined;
124
136
 
125
137
  if (transactionStep) {
126
138
  hash = await executeTransaction({ transactionStep });
@@ -160,6 +172,34 @@ export const useTransactionSteps = ({
160
172
  steps$.transaction.isExecuting.set(false);
161
173
  steps$.transaction.exist.set(false);
162
174
  }
175
+
176
+ if (hash || orderId) {
177
+ const currencyDecimal =
178
+ currencies?.find(
179
+ (currency) =>
180
+ currency.contractAddress === listingInput.listing.currencyAddress,
181
+ )?.decimals || 0;
182
+
183
+ const currencyValueRaw = Number(listingInput.listing.pricePerToken);
184
+ const currencyValueDecimal = Number(
185
+ formatUnits(BigInt(currencyValueRaw), currencyDecimal),
186
+ );
187
+
188
+ analytics.trackCreateListing({
189
+ props: {
190
+ orderbookKind,
191
+ collectionAddress,
192
+ currencyAddress: listingInput.listing.currencyAddress,
193
+ currencySymbol: '',
194
+ chainId,
195
+ txnHash: hash || '',
196
+ },
197
+ nums: {
198
+ currencyValueDecimal,
199
+ currencyValueRaw,
200
+ },
201
+ });
202
+ }
163
203
  } catch (error) {
164
204
  steps$.transaction.isExecuting.set(false);
165
205
  steps$.transaction.exist.set(false);
@@ -176,7 +216,7 @@ export const useTransactionSteps = ({
176
216
 
177
217
  const hash = await wallet.handleSendTransactionStep(
178
218
  Number(chainId),
179
- transactionStep as any,
219
+ transactionStep as WalletTransactionStep,
180
220
  );
181
221
 
182
222
  return hash;
@@ -3,12 +3,7 @@ import { useState } from 'react';
3
3
  import { parseUnits } from 'viem';
4
4
  import { dateToUnixTime } from '../../../../utils/date';
5
5
  import { ContractType } from '../../../_internal';
6
- import {
7
- useCollectible,
8
- useCollection,
9
- useCurrencies,
10
- useCurrencyOptions,
11
- } from '../../../hooks';
6
+ import { useCollectible, useCollection, useCurrencies } from '../../../hooks';
12
7
  import { useMakeOffer } from './hooks/useMakeOffer';
13
8
  import { ActionModal } from '../_internal/components/actionModal/ActionModal';
14
9
  import { ErrorModal } from '../_internal/components/actionModal/ErrorModal';
@@ -56,14 +51,12 @@ const Modal = observer(() => {
56
51
  chainId,
57
52
  collectionAddress,
58
53
  });
59
- const currencyOptions = useCurrencyOptions({ collectionAddress });
60
54
  const {
61
55
  data: currencies,
62
56
  isLoading: currenciesLoading,
63
57
  isError: currenciesIsError,
64
58
  } = useCurrencies({
65
59
  chainId,
66
- currencyOptions,
67
60
  includeNativeCurrency: false,
68
61
  });
69
62
 
@@ -1,96 +1,41 @@
1
- import '@testing-library/jest-dom/vitest';
2
1
  import {
3
2
  render,
4
3
  screen,
5
4
  cleanup,
6
- fireEvent,
7
5
  waitFor,
6
+ fireEvent,
8
7
  } from '../../../../_internal/test-utils';
9
8
  import { describe, it, expect, vi, beforeEach } from 'vitest';
10
9
  import { MakeOfferModal } from '../Modal';
11
10
  import { makeOfferModal$ } from '../store';
12
- import { useCollectible, useCollection } from '../../../../hooks';
13
- import { useMakeOffer } from '../hooks/useMakeOffer';
14
- import { useWallet } from '../../../../_internal/wallet/useWallet';
15
-
16
- // Mock the hooks
17
- vi.mock('../../../../hooks', () => ({
18
- useCollectible: vi.fn(),
19
- useCollection: vi.fn(),
20
- useCurrencies: vi.fn().mockReturnValue({
21
- data: [{ contractAddress: '0x123', symbol: 'TEST' }],
22
- isLoading: false,
23
- isError: false,
24
- }),
25
- useCurrencyOptions: vi.fn().mockReturnValue({
26
- data: [],
27
- isLoading: false,
28
- isError: false,
29
- }),
30
- useMarketplaceConfig: vi.fn().mockReturnValue({
31
- data: {
32
- collections: [
33
- {
34
- collectionAddress: '0x123',
35
- marketplaceFeePercentage: 2.5,
36
- },
37
- ],
38
- },
39
- isLoading: false,
40
- isError: false,
41
- }),
42
- useLowestListing: vi.fn().mockReturnValue({
43
- data: null,
44
- isLoading: false,
45
- isError: false,
46
- }),
47
- }));
48
-
49
- vi.mock('../../../../_internal/wallet/useWallet', () => ({
50
- useWallet: vi.fn(),
51
- }));
52
-
53
- vi.mock('../hooks/useMakeOffer', () => ({
54
- useMakeOffer: vi.fn(),
55
- }));
56
-
57
- vi.mock('@0xsequence/kit', () => ({
58
- useWaasFeeOptions: vi.fn().mockReturnValue([false, vi.fn()]),
59
- }));
11
+ import { zeroAddress } from 'viem';
12
+ import * as hooks from '../../../../hooks';
13
+
14
+ // TODO: This should be moved to a shared test file
15
+ vi.mock(import('../../../../hooks'), async (importOriginal) => {
16
+ const actual = await importOriginal();
17
+ return {
18
+ ...actual,
19
+ useCollectible: vi.fn(actual.useCollectible),
20
+ useCollection: vi.fn(actual.useCollection),
21
+ useCurrencies: vi.fn(actual.useCurrencies),
22
+ useMarketplaceConfig: vi.fn(actual.useMarketplaceConfig),
23
+ useLowestListing: vi.fn(actual.useLowestListing),
24
+ };
25
+ });
26
+
27
+ const defaultArgs = {
28
+ collectionAddress: zeroAddress,
29
+ chainId: '1',
30
+ collectibleId: '1',
31
+ };
60
32
 
61
33
  describe('MakeOfferModal', () => {
62
34
  beforeEach(() => {
63
35
  cleanup();
64
36
  // Reset all mocks
65
37
  vi.clearAllMocks();
66
-
67
- // Setup default mock values
68
- (useWallet as any).mockReturnValue({
69
- wallet: {
70
- address: () => Promise.resolve('0x123'),
71
- },
72
- isLoading: false,
73
- isError: false,
74
- });
75
-
76
- (useCollectible as any).mockReturnValue({
77
- data: { decimals: 18, name: 'Test NFT' },
78
- isLoading: false,
79
- isError: false,
80
- });
81
-
82
- (useCollection as any).mockReturnValue({
83
- data: { type: 'ERC721', name: 'Test Collection' },
84
- isLoading: false,
85
- isError: false,
86
- });
87
-
88
- (useMakeOffer as any).mockReturnValue({
89
- isLoading: false,
90
- executeApproval: vi.fn(),
91
- makeOffer: vi.fn(),
92
- tokenApprovalIsLoading: false,
93
- });
38
+ vi.resetAllMocks();
94
39
  });
95
40
 
96
41
  it('should not render when modal is closed', () => {
@@ -99,56 +44,39 @@ describe('MakeOfferModal', () => {
99
44
  });
100
45
 
101
46
  it('should render loading state', () => {
102
- (useCollectible as any).mockReturnValue({
103
- isLoading: true,
104
- });
105
-
106
- makeOfferModal$.open({
107
- collectionAddress: '0x123',
108
- chainId: '1',
109
- collectibleId: '1',
110
- });
47
+ makeOfferModal$.open(defaultArgs);
111
48
 
112
49
  render(<MakeOfferModal />);
113
50
  const loadingModal = screen.getByTestId('loading-modal');
114
51
  expect(loadingModal).toBeVisible();
115
52
  });
116
53
 
117
- it('should render error state', () => {
118
- (useCollectible as any).mockReturnValue({
54
+ it('should render error state', async () => {
55
+ // @ts-expect-error - TODO: Add a common mock object with the correct shape
56
+ vi.mocked(hooks.useCollection).mockReturnValue({
57
+ data: undefined,
58
+ isLoading: false,
119
59
  isError: true,
120
60
  });
121
61
 
122
- makeOfferModal$.open({
123
- collectionAddress: '0x123',
124
- chainId: '1',
125
- collectibleId: '1',
126
- });
62
+ makeOfferModal$.open(defaultArgs);
127
63
 
128
64
  render(<MakeOfferModal />);
129
- const errorModal = screen.getByTestId('error-modal');
65
+ const errorModal = await screen.findByTestId('error-modal');
130
66
  expect(errorModal).toBeVisible();
131
67
  });
132
68
 
133
- it('should render main form when data is loaded', () => {
134
- makeOfferModal$.open({
135
- collectionAddress: '0x123',
136
- chainId: '1',
137
- collectibleId: '1',
138
- });
69
+ it('should render main form when data is loaded', async () => {
70
+ makeOfferModal$.open(defaultArgs);
139
71
 
140
72
  render(<MakeOfferModal />);
141
73
 
142
- expect(screen.getByText('Test Collection')).toBeInTheDocument();
74
+ expect(await screen.findByText('Enter price')).toBeInTheDocument();
143
75
  });
144
76
 
145
77
  it('should reset store values when modal is closed and reopened', () => {
146
78
  // Open modal first time
147
- makeOfferModal$.open({
148
- collectionAddress: '0x123',
149
- chainId: '1',
150
- collectibleId: '1',
151
- });
79
+ makeOfferModal$.open(defaultArgs);
152
80
 
153
81
  // Set some values in the store
154
82
  makeOfferModal$.offerPrice.amountRaw.set('1000000000000000000');
@@ -162,11 +90,7 @@ describe('MakeOfferModal', () => {
162
90
  expect(makeOfferModal$.expiry.get()).toBeDefined();
163
91
 
164
92
  // Reopen modal
165
- makeOfferModal$.open({
166
- collectionAddress: '0x456',
167
- chainId: '1',
168
- collectibleId: '2',
169
- });
93
+ makeOfferModal$.open(defaultArgs);
170
94
 
171
95
  // Verify store has default values
172
96
  expect(makeOfferModal$.offerPrice.amountRaw.get()).toBe('0');
@@ -174,11 +98,7 @@ describe('MakeOfferModal', () => {
174
98
  });
175
99
 
176
100
  it('should update state based on price input', async () => {
177
- makeOfferModal$.open({
178
- collectionAddress: '0x123',
179
- chainId: '1',
180
- collectibleId: '1',
181
- });
101
+ makeOfferModal$.open(defaultArgs);
182
102
 
183
103
  render(<MakeOfferModal />);
184
104
 
@@ -186,7 +106,10 @@ describe('MakeOfferModal', () => {
186
106
  expect(makeOfferModal$.offerPrice.amountRaw.get()).toBe('0');
187
107
 
188
108
  // Find and interact with price input
189
- const priceInput = screen.getByRole('textbox', { name: 'Enter price' });
109
+
110
+ const priceInput = await screen.findByRole('textbox', {
111
+ name: 'Enter price',
112
+ });
190
113
  expect(priceInput).toBeInTheDocument();
191
114
 
192
115
  fireEvent.change(priceInput, { target: { value: '1.5' } });
@@ -31,7 +31,7 @@ export const useMakeOffer = ({
31
31
  useMarketplaceConfig();
32
32
 
33
33
  const collectionConfig = marketplaceConfig?.collections.find(
34
- (c) => c.collectionAddress === collectionAddress,
34
+ (c) => c.address === collectionAddress,
35
35
  );
36
36
 
37
37
  orderbookKind =
@@ -52,6 +52,7 @@ export const useMakeOffer = ({
52
52
  },
53
53
  });
54
54
 
55
+ // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
55
56
  useEffect(() => {
56
57
  if (tokenApproval?.step && !tokenApprovalIsLoading) {
57
58
  steps$.approval.exist.set(true);
@@ -1,5 +1,5 @@
1
1
  import type { Observable } from '@legendapp/state';
2
- import type { Address } from 'viem';
2
+ import { type Address, type Hex, formatUnits } from 'viem';
3
3
  import { OrderbookKind, type Price } from '../../../../../types';
4
4
  import {
5
5
  ExecuteType,
@@ -10,15 +10,18 @@ import {
10
10
  collectableKeys,
11
11
  getMarketplaceClient,
12
12
  } from '../../../../_internal';
13
+ import { useAnalytics } from '../../../../_internal/databeat';
13
14
  import { TransactionType } from '../../../../_internal/types';
14
15
  import type { OfferInput } from '../../../../_internal/types';
15
- import type { SignatureStep } from '../../../../_internal/utils';
16
+ import type {
17
+ SignatureStep,
18
+ TransactionStep,
19
+ } from '../../../../_internal/utils';
16
20
  import { useWallet } from '../../../../_internal/wallet/useWallet';
17
21
  import { useConfig, useCurrency } from '../../../../hooks';
18
22
  import { useGenerateOfferTransaction } from '../../../../hooks/useGenerateOfferTransaction';
19
23
  import { useTransactionStatusModal } from '../../_internal/components/transactionStatusModal';
20
24
  import type { ModalCallbacks } from '../../_internal/types';
21
-
22
25
  export type ExecutionState = 'approval' | 'offer' | null;
23
26
 
24
27
  interface UseTransactionStepsArgs {
@@ -44,6 +47,7 @@ export const useTransactionSteps = ({
44
47
  const expiry = new Date(Number(offerInput.offer.expiry) * 1000);
45
48
  const { show: showTransactionStatusModal } = useTransactionStatusModal();
46
49
  const sdkConfig = useConfig();
50
+ const analytics = useAnalytics();
47
51
  const marketplaceClient = getMarketplaceClient(chainId, sdkConfig);
48
52
  const { generateOfferTransactionAsync, isPending: generatingSteps } =
49
53
  useGenerateOfferTransaction({
@@ -96,7 +100,7 @@ export const useTransactionSteps = ({
96
100
 
97
101
  const hash = await wallet.handleSendTransactionStep(
98
102
  Number(chainId),
99
- approvalStep as any,
103
+ approvalStep as TransactionStep,
100
104
  );
101
105
 
102
106
  await wallet.handleConfirmTransactionStep(hash, Number(chainId));
@@ -127,7 +131,8 @@ export const useTransactionSteps = ({
127
131
  throw new Error('No transaction or signature step found');
128
132
  }
129
133
 
130
- let hash, orderId: string | undefined;
134
+ let hash: Hex | undefined;
135
+ let orderId: string | undefined;
131
136
 
132
137
  if (transactionStep) {
133
138
  hash = await executeTransaction({ transactionStep });
@@ -173,6 +178,29 @@ export const useTransactionSteps = ({
173
178
  steps$.transaction.isExecuting.set(false);
174
179
  steps$.transaction.exist.set(false);
175
180
  }
181
+
182
+ if (hash || orderId) {
183
+ const currencyDecimal = currency?.decimals || 0;
184
+ const currencyValueRaw = Number(offerInput.offer.pricePerToken);
185
+ const currencyValueDecimal = Number(
186
+ formatUnits(BigInt(currencyValueRaw), currencyDecimal),
187
+ );
188
+
189
+ analytics.trackCreateOffer({
190
+ props: {
191
+ orderbookKind,
192
+ collectionAddress,
193
+ currencyAddress: offerInput.offer.currencyAddress,
194
+ currencySymbol: currency?.symbol || '',
195
+ chainId,
196
+ txnHash: hash || '',
197
+ },
198
+ nums: {
199
+ currencyValueDecimal,
200
+ currencyValueRaw,
201
+ },
202
+ });
203
+ }
176
204
  } catch (error) {
177
205
  steps$.transaction.isExecuting.set(false);
178
206
  steps$.transaction.exist.set(false);
@@ -191,7 +219,7 @@ export const useTransactionSteps = ({
191
219
 
192
220
  const hash = await wallet.handleSendTransactionStep(
193
221
  Number(chainId),
194
- transactionStep as any,
222
+ transactionStep as TransactionStep,
195
223
  );
196
224
 
197
225
  return hash;
@@ -11,8 +11,8 @@ import { LoadingModal } from '../_internal/components/actionModal/LoadingModal';
11
11
  import TokenPreview from '../_internal/components/tokenPreview';
12
12
  import TransactionDetails from '../_internal/components/transactionDetails';
13
13
  import TransactionHeader from '../_internal/components/transactionHeader';
14
- import { sellModal$ } from './store';
15
14
  import { useSell } from './hooks/useSell';
15
+ import { sellModal$ } from './store';
16
16
 
17
17
  export const SellModal = () => {
18
18
  return <Show if={sellModal$.isOpen}>{() => <Modal />}</Show>;
@@ -58,6 +58,8 @@ const Modal = observer(() => {
58
58
  collectible?.decimals || 0,
59
59
  ).toString()
60
60
  : '1',
61
+ pricePerToken: order?.priceAmount ?? '',
62
+ currencyAddress: order?.priceCurrencyAddress ?? '',
61
63
  },
62
64
  ],
63
65
  callbacks,
@@ -1,4 +1,3 @@
1
- import '@testing-library/jest-dom/vitest';
2
1
  import { render, screen, cleanup } from '../../../../_internal/test-utils';
3
2
  import {
4
3
  describe,
@@ -104,13 +103,15 @@ describe('SellModal', () => {
104
103
  });
105
104
 
106
105
  it('should render main modal when data is loaded', async () => {
107
- vi.mocked(useCollection as any).mockReturnValue({
106
+ vi.mocked(useCollection).mockReturnValue({
107
+ // @ts-expect-error - TODO: mock this better
108
108
  data: {},
109
109
  isLoading: false,
110
110
  isError: false,
111
111
  });
112
112
 
113
- vi.mocked(useCurrency as any).mockReturnValue({
113
+ vi.mocked(useCurrency).mockReturnValue({
114
+ // @ts-expect-error - TODO: mock this better
114
115
  data: {},
115
116
  isLoading: false,
116
117
  isError: false,
@@ -5,7 +5,7 @@ import {
5
5
  type OrderData,
6
6
  StepType,
7
7
  } from '../../../../_internal';
8
- import { useQuery } from '@tanstack/react-query';
8
+ import { skipToken, useQuery } from '@tanstack/react-query';
9
9
  import { useWallet } from '../../../../_internal/wallet/useWallet';
10
10
  import { useConfig } from '../../../../hooks/useConfig';
11
11
  import { useFees } from '../../BuyModal/hooks/useFees';
@@ -30,38 +30,40 @@ export const useGetTokenApprovalData = (
30
30
 
31
31
  const { data, isLoading, isSuccess } = useQuery({
32
32
  queryKey: ['token-approval-data', params.ordersData],
33
- queryFn: async () => {
34
- const address = await wallet!.address();
35
- const args = {
36
- collectionAddress: params.collectionAddress,
37
- walletType: wallet!.walletKind,
38
- seller: address,
39
- marketplace: params.marketplace,
40
- ordersData: params.ordersData,
41
- additionalFees: [
42
- {
43
- amount,
44
- receiver,
45
- },
46
- ],
47
- } satisfies GenerateSellTransactionArgs;
48
- const steps = await marketplaceClient
49
- .generateSellTransaction(args)
50
- .then((resp) => resp.steps);
33
+ queryFn: wallet
34
+ ? async () => {
35
+ const address = await wallet.address();
36
+ const args = {
37
+ collectionAddress: params.collectionAddress,
38
+ walletType: wallet.walletKind,
39
+ seller: address,
40
+ marketplace: params.marketplace,
41
+ ordersData: params.ordersData,
42
+ additionalFees: [
43
+ {
44
+ amount,
45
+ receiver,
46
+ },
47
+ ],
48
+ } satisfies GenerateSellTransactionArgs;
49
+ const steps = await marketplaceClient
50
+ .generateSellTransaction(args)
51
+ .then((resp) => resp.steps);
51
52
 
52
- const tokenApprovalStep = steps.find(
53
- (step) => step.id === StepType.tokenApproval,
54
- );
55
- if (!tokenApprovalStep) {
56
- return {
57
- step: null,
58
- };
59
- }
53
+ const tokenApprovalStep = steps.find(
54
+ (step) => step.id === StepType.tokenApproval,
55
+ );
56
+ if (!tokenApprovalStep) {
57
+ return {
58
+ step: null,
59
+ };
60
+ }
60
61
 
61
- return {
62
- step: tokenApprovalStep,
63
- };
64
- },
62
+ return {
63
+ step: tokenApprovalStep,
64
+ };
65
+ }
66
+ : skipToken,
65
67
  enabled: !!wallet && !!params.collectionAddress,
66
68
  });
67
69
 
@@ -1,20 +1,23 @@
1
1
  import type { Observable } from '@legendapp/state';
2
+ import { useEffect } from 'react';
3
+ import type { MarketplaceKind, TransactionSteps } from '../../../../_internal';
2
4
  import type { ModalCallbacks } from '../../_internal/types';
3
5
  import { useGetTokenApprovalData } from './useGetTokenApproval';
4
6
  import { useTransactionSteps } from './useTransactionSteps';
5
- import { useEffect } from 'react';
6
- import type {
7
- MarketplaceKind,
8
- OrderData,
9
- TransactionSteps,
10
- } from '../../../../_internal';
7
+
8
+ export type SellOrder = {
9
+ orderId: string;
10
+ quantity: string;
11
+ pricePerToken: string;
12
+ currencyAddress: string;
13
+ };
11
14
 
12
15
  interface UseSellArgs {
13
16
  collectibleId: string;
14
17
  chainId: string;
15
18
  collectionAddress: string;
16
19
  marketplace: MarketplaceKind;
17
- ordersData: Array<OrderData>;
20
+ ordersData: Array<SellOrder>;
18
21
  callbacks?: ModalCallbacks;
19
22
  closeMainModal: () => void;
20
23
  steps$: Observable<TransactionSteps>;
@@ -38,6 +41,7 @@ export const useSell = ({
38
41
  marketplace,
39
42
  });
40
43
 
44
+ // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
41
45
  useEffect(() => {
42
46
  if (tokenApproval?.step && !tokenApprovalIsLoading) {
43
47
  steps$.approval.exist.set(true);