@0xsequence/marketplace-sdk 0.5.3 → 0.5.5

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 (77) hide show
  1. package/dist/{builder-types-wOwfTJpd.d.ts → builder-types-Jl3Ymws8.d.ts} +1 -1
  2. package/dist/chunk-3BLBZYQX.js +56 -0
  3. package/dist/chunk-3BLBZYQX.js.map +1 -0
  4. package/dist/{chunk-BZD2LDJJ.js → chunk-7C7ADZ2H.js} +2 -2
  5. package/dist/{chunk-H5YWG6WN.js → chunk-AXTDPTRD.js} +317 -147
  6. package/dist/chunk-AXTDPTRD.js.map +1 -0
  7. package/dist/{chunk-BVXIRVEC.js → chunk-CIPPTQDA.js} +219 -72
  8. package/dist/chunk-CIPPTQDA.js.map +1 -0
  9. package/dist/{chunk-Y7YTLAO2.js → chunk-P7UNMRZ5.js} +3 -3
  10. package/dist/{chunk-WSCUPAGR.js → chunk-SA3U25NU.js} +2 -1
  11. package/dist/{chunk-WSCUPAGR.js.map → chunk-SA3U25NU.js.map} +1 -1
  12. package/dist/{chunk-MWDG7UTB.js → chunk-ZBLU3Q22.js} +1 -1
  13. package/dist/{create-config-Bltg8Enl.d.ts → create-config-DOUq8Day.d.ts} +2 -2
  14. package/dist/index.d.ts +4 -3
  15. package/dist/index.js +8 -8
  16. package/dist/{sdk-config-B32_2bG3.d.ts → marketplace.gen-D0ADxbfH.d.ts} +1 -24
  17. package/dist/react/_internal/api/index.d.ts +4 -2
  18. package/dist/react/_internal/api/index.js +1 -1
  19. package/dist/react/_internal/databeat/index.css +82 -0
  20. package/dist/react/_internal/databeat/index.css.map +1 -0
  21. package/dist/react/_internal/databeat/index.d.ts +68 -0
  22. package/dist/react/_internal/databeat/index.js +26 -0
  23. package/dist/react/_internal/databeat/index.js.map +1 -0
  24. package/dist/react/_internal/index.d.ts +6 -5
  25. package/dist/react/_internal/index.js +1 -1
  26. package/dist/react/_internal/wagmi/index.d.ts +4 -3
  27. package/dist/react/hooks/index.d.ts +446 -5
  28. package/dist/react/hooks/index.js +19 -5
  29. package/dist/react/index.d.ts +7 -6
  30. package/dist/react/index.js +22 -7
  31. package/dist/react/ssr/index.js +1 -0
  32. package/dist/react/ssr/index.js.map +1 -1
  33. package/dist/react/ui/components/collectible-card/index.d.ts +4 -3
  34. package/dist/react/ui/components/collectible-card/index.js +8 -7
  35. package/dist/react/ui/components/marketplace-logos/index.js +1 -1
  36. package/dist/react/ui/index.d.ts +4 -3
  37. package/dist/react/ui/index.js +8 -7
  38. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +4 -3
  39. package/dist/react/ui/modals/_internal/components/actionModal/index.js +6 -6
  40. package/dist/sdk-config-xWkdBdrL.d.ts +24 -0
  41. package/dist/{services-BRBVE0mm.d.ts → services-Dd2MoBTM.d.ts} +2 -1
  42. package/dist/types/index.d.ts +4 -3
  43. package/dist/types/index.js +1 -1
  44. package/dist/{types-BY3husBh.d.ts → types-vOfhbBkR.d.ts} +3 -2
  45. package/dist/utils/abi/index.js +5 -5
  46. package/dist/utils/index.d.ts +4 -3
  47. package/dist/utils/index.js +8 -8
  48. package/package.json +2 -1
  49. package/src/react/_internal/api/query-keys.ts +1 -0
  50. package/src/react/_internal/databeat/index.ts +63 -0
  51. package/src/react/_internal/databeat/types.ts +70 -0
  52. package/src/react/hooks/__tests__/useComparePrices.test.tsx +215 -0
  53. package/src/react/hooks/__tests__/useConvertPriceToUSD.test.tsx +173 -0
  54. package/src/react/hooks/__tests__/useListCollectiblesPaginated.test.tsx +217 -0
  55. package/src/react/hooks/index.ts +3 -0
  56. package/src/react/hooks/useComparePrices.tsx +106 -0
  57. package/src/react/hooks/useConvertPriceToUSD.tsx +102 -0
  58. package/src/react/hooks/useFilters.tsx +9 -3
  59. package/src/react/hooks/useListCollectiblesPaginated.tsx +78 -0
  60. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +1 -0
  61. package/src/react/ui/components/collectible-card/Footer.tsx +10 -2
  62. package/src/react/ui/modals/BuyModal/hooks/useBuyCollectable.ts +30 -3
  63. package/src/react/ui/modals/CreateListingModal/hooks/useTransactionSteps.tsx +40 -4
  64. package/src/react/ui/modals/MakeOfferModal/hooks/useTransactionSteps.tsx +26 -2
  65. package/src/react/ui/modals/SellModal/Modal.tsx +3 -1
  66. package/src/react/ui/modals/SellModal/hooks/useSell.tsx +10 -7
  67. package/src/react/ui/modals/SellModal/hooks/useTransactionSteps.tsx +51 -13
  68. package/src/react/ui/modals/_internal/components/floorPriceText/index.tsx +30 -12
  69. package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +51 -4
  70. package/src/react/ui/modals/_internal/components/priceInput/index.tsx +24 -3
  71. package/tsconfig.tsbuildinfo +1 -1
  72. package/dist/chunk-BVXIRVEC.js.map +0 -1
  73. package/dist/chunk-H5YWG6WN.js.map +0 -1
  74. /package/dist/{chunk-BZD2LDJJ.js.map → chunk-7C7ADZ2H.js.map} +0 -0
  75. /package/dist/{chunk-Y7YTLAO2.js.map → chunk-P7UNMRZ5.js.map} +0 -0
  76. /package/dist/{chunk-MWDG7UTB.js.map → chunk-ZBLU3Q22.js.map} +0 -0
  77. /package/src/react/ui/modals/BuyModal/hooks/__tests__/{useBuyCollectable.test.tsx → useBuyCollectable.test.tsx.bak} +0 -0
@@ -0,0 +1,217 @@
1
+ import { waitFor } from '@testing-library/react';
2
+ import { http, HttpResponse } from 'msw';
3
+ import { zeroAddress } from 'viem';
4
+ import { describe, expect, it } from 'vitest';
5
+ import {
6
+ mockCollectibleOrder,
7
+ mockMarketplaceEndpoint,
8
+ } from '../../_internal/api/__mocks__/marketplace.msw';
9
+ import { OrderSide } from '../../_internal/api/marketplace.gen';
10
+ import { renderHook } from '../../_internal/test-utils';
11
+ import { server } from '../../_internal/test/setup';
12
+ import { useListCollectiblesPaginated } from '../useListCollectiblesPaginated';
13
+ import type { UseListCollectiblesPaginatedArgs } from '../useListCollectiblesPaginated';
14
+
15
+ describe('useListCollectiblesPaginated', () => {
16
+ const defaultArgs: UseListCollectiblesPaginatedArgs = {
17
+ chainId: '1',
18
+ collectionAddress: zeroAddress,
19
+ side: OrderSide.listing,
20
+ query: {
21
+ enabled: true,
22
+ page: 1,
23
+ pageSize: 30,
24
+ },
25
+ };
26
+
27
+ it('should fetch collectibles successfully', async () => {
28
+ // Set up mock response
29
+ server.use(
30
+ http.post(mockMarketplaceEndpoint('ListCollectibles'), () => {
31
+ return HttpResponse.json({
32
+ collectibles: [mockCollectibleOrder],
33
+ page: { page: 1, pageSize: 30, more: false },
34
+ });
35
+ }),
36
+ );
37
+
38
+ const { result } = renderHook(() =>
39
+ useListCollectiblesPaginated(defaultArgs),
40
+ );
41
+
42
+ // Wait for the query to complete
43
+ await waitFor(() => {
44
+ expect(result.current.isSuccess).toBe(true);
45
+ });
46
+
47
+ // Verify the data
48
+ expect(result.current.data?.collectibles).toEqual([mockCollectibleOrder]);
49
+ expect(result.current.data?.page).toEqual({
50
+ page: 1,
51
+ pageSize: 30,
52
+ more: false,
53
+ });
54
+ });
55
+
56
+ it('should handle error states', async () => {
57
+ // Override the handler to return an error
58
+ server.use(
59
+ http.post(mockMarketplaceEndpoint('ListCollectibles'), () => {
60
+ return HttpResponse.json(
61
+ { error: { message: 'Failed to fetch collectibles' } },
62
+ { status: 500 },
63
+ );
64
+ }),
65
+ );
66
+
67
+ const { result } = renderHook(() =>
68
+ useListCollectiblesPaginated(defaultArgs),
69
+ );
70
+
71
+ // Wait for the error state
72
+ await waitFor(() => {
73
+ expect(result.current.isError).toBe(true);
74
+ });
75
+
76
+ expect(result.current.error).toBeDefined();
77
+ expect(result.current.data).toBeUndefined();
78
+ });
79
+
80
+ it('should handle pagination correctly', async () => {
81
+ // Set up mock response for page 2
82
+ const modifiedCollectibleOrder = {
83
+ ...mockCollectibleOrder,
84
+ metadata: {
85
+ ...mockCollectibleOrder.metadata,
86
+ tokenId: '2',
87
+ },
88
+ };
89
+
90
+ server.use(
91
+ http.post(mockMarketplaceEndpoint('ListCollectibles'), () => {
92
+ return HttpResponse.json({
93
+ collectibles: [modifiedCollectibleOrder],
94
+ page: { page: 2, pageSize: 20, more: false },
95
+ });
96
+ }),
97
+ );
98
+
99
+ const paginatedArgs: UseListCollectiblesPaginatedArgs = {
100
+ ...defaultArgs,
101
+ query: {
102
+ enabled: true,
103
+ page: 2,
104
+ pageSize: 20,
105
+ },
106
+ };
107
+
108
+ const { result } = renderHook(() =>
109
+ useListCollectiblesPaginated(paginatedArgs),
110
+ );
111
+
112
+ // Wait for the query to complete
113
+ await waitFor(() => {
114
+ expect(result.current.isSuccess).toBe(true);
115
+ });
116
+
117
+ // Verify the data for page 2
118
+ expect(result.current.data?.collectibles[0].metadata.tokenId).toBe('2');
119
+ expect(result.current.data?.page).toEqual({
120
+ page: 2,
121
+ pageSize: 20,
122
+ more: false,
123
+ });
124
+ });
125
+
126
+ it('should refetch when args change', async () => {
127
+ // Set up initial mock response
128
+ server.use(
129
+ http.post(mockMarketplaceEndpoint('ListCollectibles'), () => {
130
+ return HttpResponse.json({
131
+ collectibles: [mockCollectibleOrder],
132
+ page: { page: 1, pageSize: 30, more: true },
133
+ });
134
+ }),
135
+ );
136
+
137
+ let currentArgs = defaultArgs;
138
+ const { result, rerender } = renderHook(() =>
139
+ useListCollectiblesPaginated(currentArgs),
140
+ );
141
+
142
+ // Wait for initial data
143
+ await waitFor(() => {
144
+ expect(result.current.isSuccess).toBe(true);
145
+ });
146
+
147
+ // Change args and rerender
148
+ currentArgs = {
149
+ ...defaultArgs,
150
+ query: {
151
+ ...defaultArgs.query,
152
+ page: 2,
153
+ },
154
+ };
155
+
156
+ // Set up mock response for page 2
157
+ const modifiedCollectibleOrder = {
158
+ ...mockCollectibleOrder,
159
+ metadata: {
160
+ ...mockCollectibleOrder.metadata,
161
+ tokenId: '2',
162
+ },
163
+ };
164
+
165
+ server.use(
166
+ http.post(mockMarketplaceEndpoint('ListCollectibles'), () => {
167
+ return HttpResponse.json({
168
+ collectibles: [modifiedCollectibleOrder],
169
+ page: { page: 2, pageSize: 30, more: false },
170
+ });
171
+ }),
172
+ );
173
+
174
+ rerender();
175
+
176
+ // Wait for new data
177
+ await waitFor(() => {
178
+ expect(result.current.data?.page?.page).toBe(2);
179
+ });
180
+
181
+ // Verify new data
182
+ expect(result.current.data?.collectibles[0].metadata.tokenId).toBe('2');
183
+ });
184
+
185
+ it('should not fetch when enabled is false', async () => {
186
+ // Set up a mock handler to ensure no requests are made
187
+ let requestMade = false;
188
+ server.use(
189
+ http.post(mockMarketplaceEndpoint('ListCollectibles'), () => {
190
+ requestMade = true;
191
+ return HttpResponse.json({
192
+ collectibles: [mockCollectibleOrder],
193
+ page: { page: 1, pageSize: 30, more: false },
194
+ });
195
+ }),
196
+ );
197
+
198
+ const disabledArgs: UseListCollectiblesPaginatedArgs = {
199
+ ...defaultArgs,
200
+ query: {
201
+ enabled: false,
202
+ page: 1,
203
+ pageSize: 30,
204
+ },
205
+ };
206
+
207
+ const { result } = renderHook(() =>
208
+ useListCollectiblesPaginated(disabledArgs),
209
+ );
210
+
211
+ // For disabled queries, we expect no loading state and no data
212
+ expect(result.current.isLoading).toBe(false);
213
+ expect(result.current.data).toBeUndefined();
214
+ expect(result.current.error).toBeNull();
215
+ expect(requestMade).toBe(false);
216
+ });
217
+ });
@@ -4,7 +4,9 @@ export * from './useCountOfCollectables';
4
4
  export * from './useCollectible';
5
5
  export * from './useCollection';
6
6
  export * from './useCollectionBalanceDetails';
7
+ export * from './useComparePrices';
7
8
  export * from './useConfig';
9
+ export * from './useConvertPriceToUSD';
8
10
  export * from './useCurrencies';
9
11
  export * from './useCurrency';
10
12
  export * from './useFilters';
@@ -13,6 +15,7 @@ export * from './useHighestOffer';
13
15
  export * from './useListBalances';
14
16
  export * from './useListCollectibleActivities';
15
17
  export * from './useListCollectibles';
18
+ export * from './useListCollectiblesPaginated';
16
19
  export * from './useListCollectionActivities';
17
20
  export * from './useListOffersForCollectible';
18
21
  export * from './useCountOffersForCollectible';
@@ -0,0 +1,106 @@
1
+ import { queryOptions, useQuery } from '@tanstack/react-query';
2
+ import { z } from 'zod';
3
+ import type { SdkConfig } from '../../types';
4
+ import {
5
+ AddressSchema,
6
+ ChainIdSchema,
7
+ QueryArgSchema,
8
+ currencyKeys,
9
+ } from '../_internal';
10
+ import { useConfig } from './useConfig';
11
+ import { convertPriceToUSD } from './useConvertPriceToUSD';
12
+
13
+ const ChainIdCoerce = ChainIdSchema.transform((val) => val.toString());
14
+
15
+ const UseComparePricesArgsSchema = z.object({
16
+ chainId: ChainIdCoerce,
17
+ // First price details
18
+ priceAmountRaw: z.string(),
19
+ priceCurrencyAddress: AddressSchema,
20
+ // Second price details (to compare against)
21
+ compareToPriceAmountRaw: z.string(),
22
+ compareToPriceCurrencyAddress: AddressSchema,
23
+ query: QueryArgSchema,
24
+ });
25
+
26
+ type UseComparePricesArgs = z.input<typeof UseComparePricesArgsSchema>;
27
+
28
+ export type UseComparePricesReturn = {
29
+ percentageDifference: number;
30
+ percentageDifferenceFormatted: string;
31
+ status: 'above' | 'same' | 'below';
32
+ };
33
+
34
+ const comparePrices = async (
35
+ args: UseComparePricesArgs,
36
+ config: SdkConfig,
37
+ ): Promise<UseComparePricesReturn> => {
38
+ const parsedArgs = UseComparePricesArgsSchema.parse(args);
39
+ const [priceUSD, compareToPriceUSD] = await Promise.all([
40
+ convertPriceToUSD(
41
+ {
42
+ chainId: parsedArgs.chainId,
43
+ currencyAddress: parsedArgs.priceCurrencyAddress,
44
+ amountRaw: parsedArgs.priceAmountRaw,
45
+ query: {},
46
+ },
47
+ config,
48
+ ),
49
+ convertPriceToUSD(
50
+ {
51
+ chainId: parsedArgs.chainId,
52
+ currencyAddress: parsedArgs.compareToPriceCurrencyAddress,
53
+ amountRaw: parsedArgs.compareToPriceAmountRaw,
54
+ query: {},
55
+ },
56
+ config,
57
+ ),
58
+ ]);
59
+ const difference = priceUSD.usdAmount - compareToPriceUSD.usdAmount;
60
+
61
+ if (compareToPriceUSD.usdAmount === 0) {
62
+ throw new Error('Cannot compare to zero price');
63
+ }
64
+
65
+ const percentageDifference = (difference / compareToPriceUSD.usdAmount) * 100;
66
+ const isAbove = percentageDifference > 0;
67
+ const isSame = percentageDifference === 0;
68
+
69
+ return {
70
+ percentageDifference,
71
+ percentageDifferenceFormatted: Math.abs(percentageDifference).toFixed(2),
72
+ status: isAbove ? 'above' : isSame ? 'same' : 'below',
73
+ };
74
+ };
75
+
76
+ export const comparePricesOptions = (
77
+ args: UseComparePricesArgs,
78
+ config: SdkConfig,
79
+ ) => {
80
+ return queryOptions({
81
+ ...args.query,
82
+ queryKey: [...currencyKeys.conversion, 'compare', args],
83
+ queryFn: () => comparePrices(args, config),
84
+ });
85
+ };
86
+
87
+ /**
88
+ * Hook to compare prices between different currencies by converting both to USD
89
+ * @param args - The arguments for the hook
90
+ * @returns The percentage difference between the two prices
91
+ * @example
92
+ * ```ts
93
+ * const { data } = useComparePrices({
94
+ * chainId: 1,
95
+ * priceAmountRaw: "1000000000000000000",
96
+ * priceCurrencyAddress: "0x0000000000000000000000000000000000000000",
97
+ * });
98
+ *
99
+ * console.log(data);
100
+ * // { percentageDifference: 10, percentageDifferenceFormatted: "10.00", isAbove: true, isSame: false, isBelow: false }
101
+ * ```
102
+ */
103
+ export const useComparePrices = (args: UseComparePricesArgs) => {
104
+ const config = useConfig();
105
+ return useQuery(comparePricesOptions(args, config));
106
+ };
@@ -0,0 +1,102 @@
1
+ import { queryOptions, useQuery } from '@tanstack/react-query';
2
+ import { formatUnits } from 'viem';
3
+ import { z } from 'zod';
4
+ import type { SdkConfig } from '../../types';
5
+ import {
6
+ AddressSchema,
7
+ ChainIdSchema,
8
+ QueryArgSchema,
9
+ currencyKeys,
10
+ getQueryClient,
11
+ } from '../_internal';
12
+ import { useConfig } from './useConfig';
13
+ import { currenciesOptions } from './useCurrencies';
14
+
15
+ const ChainIdCoerce = ChainIdSchema.transform((val) => val.toString());
16
+
17
+ const UseConvertPriceToUSDArgsSchema = z.object({
18
+ chainId: ChainIdCoerce,
19
+ currencyAddress: AddressSchema,
20
+ amountRaw: z.string(),
21
+ query: QueryArgSchema,
22
+ });
23
+
24
+ export type UseConvertPriceToUSDArgs = z.input<
25
+ typeof UseConvertPriceToUSDArgsSchema
26
+ >;
27
+
28
+ export type UseConvertPriceToUSDReturn = {
29
+ usdAmount: number;
30
+ usdAmountFormatted: string;
31
+ };
32
+
33
+ export const convertPriceToUSD = async (
34
+ args: UseConvertPriceToUSDArgs,
35
+ config: SdkConfig,
36
+ ): Promise<UseConvertPriceToUSDReturn> => {
37
+ const parsedArgs = UseConvertPriceToUSDArgsSchema.parse(args);
38
+ const queryClient = getQueryClient();
39
+ const currencies = await queryClient.fetchQuery(
40
+ currenciesOptions(
41
+ {
42
+ chainId: parsedArgs.chainId,
43
+ },
44
+ config,
45
+ ),
46
+ );
47
+ const currencyDetails = currencies.find(
48
+ (c) =>
49
+ c.contractAddress.toLowerCase() ===
50
+ parsedArgs.currencyAddress.toLowerCase(),
51
+ );
52
+
53
+ if (!currencyDetails) {
54
+ throw new Error('Currency not found');
55
+ }
56
+
57
+ const amountDecimal = Number(
58
+ formatUnits(BigInt(parsedArgs.amountRaw), currencyDetails.decimals),
59
+ );
60
+ const usdAmount = amountDecimal * currencyDetails.exchangeRate;
61
+
62
+ return {
63
+ usdAmount,
64
+ usdAmountFormatted: usdAmount.toFixed(2),
65
+ };
66
+ };
67
+
68
+ export const convertPriceToUSDOptions = (
69
+ args: UseConvertPriceToUSDArgs,
70
+ config: SdkConfig,
71
+ ) => {
72
+ return queryOptions({
73
+ ...args.query,
74
+ queryKey: [
75
+ ...currencyKeys.conversion,
76
+ args.chainId,
77
+ args.currencyAddress,
78
+ args.amountRaw,
79
+ ],
80
+ queryFn: () => convertPriceToUSD(args, config),
81
+ });
82
+ };
83
+
84
+ /**
85
+ * Hook to convert a price amount from a specific currency to USD
86
+ * @returns The price amount in USD and formatted USD amount
87
+ * @example
88
+ * ```ts
89
+ * const { data } = useConvertPriceToUSD({
90
+ * chainId: 1,
91
+ * currencyAddress: "0x0000000000000000000000000000000000000000",
92
+ * amountRaw: "1000000000000000000",
93
+ * });
94
+ *
95
+ * console.log(data);
96
+ * // { usdAmount: 1000, usdAmountFormatted: "1000.00" }
97
+ * ```
98
+ */
99
+ export const useConvertPriceToUSD = (args: UseConvertPriceToUSDArgs) => {
100
+ const config = useConfig();
101
+ return useQuery(convertPriceToUSDOptions(args, config));
102
+ };
@@ -1,6 +1,8 @@
1
+ import type { PropertyFilter } from '@0xsequence/metadata';
1
2
  import { queryOptions, useQuery } from '@tanstack/react-query';
2
3
  import { z } from 'zod';
3
4
  import { FilterCondition, type SdkConfig } from '../../types';
5
+ import { compareAddress } from '../../utils';
4
6
  import {
5
7
  AddressSchema,
6
8
  ChainIdSchema,
@@ -11,8 +13,6 @@ import {
11
13
  } from '../_internal';
12
14
  import { useConfig } from './useConfig';
13
15
  import { marketplaceConfigOptions } from './useMarketplaceConfig';
14
- import { compareAddress } from '../../utils';
15
- import type { PropertyFilter } from '@0xsequence/metadata';
16
16
 
17
17
  const UseFiltersSchema = z.object({
18
18
  chainId: ChainIdSchema.pipe(z.coerce.string()),
@@ -45,7 +45,13 @@ export const fetchFilters = async (args: UseFiltersArgs, config: SdkConfig) => {
45
45
  compareAddress(c.address, parsedArgs.collectionAddress),
46
46
  )?.filterSettings;
47
47
 
48
- if (!collectionFilters) return filters;
48
+ if (
49
+ !collectionFilters?.exclusions ||
50
+ collectionFilters.exclusions.length === 0 ||
51
+ !collectionFilters.filterOrder ||
52
+ collectionFilters.filterOrder.length === 0
53
+ )
54
+ return filters;
49
55
 
50
56
  const { filterOrder, exclusions } = collectionFilters;
51
57
 
@@ -0,0 +1,78 @@
1
+ import { queryOptions, useQuery } from '@tanstack/react-query';
2
+ import { z } from 'zod';
3
+ import type { Page, SdkConfig } from '../../types';
4
+ import {
5
+ AddressSchema,
6
+ ChainIdSchema,
7
+ type ListCollectiblesArgs,
8
+ collectableKeys,
9
+ getMarketplaceClient,
10
+ } from '../_internal';
11
+ import { listCollectiblesArgsSchema } from '../_internal/api/zod-schema';
12
+ import { useConfig } from './useConfig';
13
+
14
+ const UseListCollectiblesPaginatedArgsSchema = listCollectiblesArgsSchema
15
+ .omit({
16
+ contractAddress: true,
17
+ })
18
+ .extend({
19
+ collectionAddress: AddressSchema,
20
+ chainId: ChainIdSchema.pipe(z.coerce.string()),
21
+ query: z
22
+ .object({
23
+ enabled: z.boolean().optional(),
24
+ page: z.number().optional().default(1),
25
+ pageSize: z.number().optional().default(30),
26
+ })
27
+ .optional()
28
+ .default({}),
29
+ });
30
+
31
+ export type UseListCollectiblesPaginatedArgs = z.infer<
32
+ typeof UseListCollectiblesPaginatedArgsSchema
33
+ >;
34
+
35
+ export type UseListCollectiblesPaginatedReturn = Awaited<
36
+ ReturnType<typeof fetchCollectiblesPaginated>
37
+ >;
38
+
39
+ const fetchCollectiblesPaginated = async (
40
+ args: UseListCollectiblesPaginatedArgs,
41
+ marketplaceClient: Awaited<ReturnType<typeof getMarketplaceClient>>,
42
+ ) => {
43
+ const parsedArgs = UseListCollectiblesPaginatedArgsSchema.parse(args);
44
+ const page: Page = {
45
+ page: parsedArgs.query?.page ?? 1,
46
+ pageSize: parsedArgs.query?.pageSize ?? 30,
47
+ };
48
+
49
+ const arg = {
50
+ ...parsedArgs,
51
+ contractAddress: parsedArgs.collectionAddress,
52
+ page,
53
+ } as ListCollectiblesArgs;
54
+
55
+ return marketplaceClient.listCollectibles(arg);
56
+ };
57
+
58
+ export const listCollectiblesPaginatedOptions = (
59
+ args: UseListCollectiblesPaginatedArgs,
60
+ config: SdkConfig,
61
+ ) => {
62
+ const marketplaceClient = getMarketplaceClient(
63
+ args.chainId as string,
64
+ config,
65
+ );
66
+ return queryOptions({
67
+ queryKey: [...collectableKeys.lists, 'paginated', args],
68
+ queryFn: () => fetchCollectiblesPaginated(args, marketplaceClient),
69
+ enabled: args.query?.enabled ?? true,
70
+ });
71
+ };
72
+
73
+ export const useListCollectiblesPaginated = (
74
+ args: UseListCollectiblesPaginatedArgs,
75
+ ) => {
76
+ const config = useConfig();
77
+ return useQuery(listCollectiblesPaginatedOptions(args, config));
78
+ };
@@ -184,6 +184,7 @@ export function CollectibleCard({
184
184
  lowestListingPriceAmount={lowestListing?.order?.priceAmount}
185
185
  lowestListingCurrency={lowestListingCurrency}
186
186
  balance={balance}
187
+ decimals={collectibleMetadata?.decimals}
187
188
  />
188
189
 
189
190
  {(highestOffer || lowestListing) && (
@@ -15,6 +15,7 @@ const formatPrice = (amount: string, currency: Currency): string => {
15
15
  type FooterProps = {
16
16
  name: string;
17
17
  type?: ContractType;
18
+ decimals?: number;
18
19
  onOfferClick?: () => void;
19
20
  highestOffer?: Order;
20
21
  lowestListingPriceAmount?: string;
@@ -25,6 +26,7 @@ type FooterProps = {
25
26
  export const Footer = ({
26
27
  name,
27
28
  type,
29
+ decimals,
28
30
  onOfferClick,
29
31
  highestOffer,
30
32
  lowestListingPriceAmount,
@@ -104,7 +106,11 @@ export const Footer = ({
104
106
  </Text>
105
107
  </Box>
106
108
 
107
- <TokenTypeBalancePill balance={balance} type={type as ContractType} />
109
+ <TokenTypeBalancePill
110
+ balance={balance}
111
+ type={type as ContractType}
112
+ decimals={decimals}
113
+ />
108
114
  </Box>
109
115
  );
110
116
  };
@@ -112,14 +118,16 @@ export const Footer = ({
112
118
  const TokenTypeBalancePill = ({
113
119
  balance,
114
120
  type,
121
+ decimals,
115
122
  }: {
116
123
  balance?: string;
117
124
  type: ContractType;
125
+ decimals?: number;
118
126
  }) => {
119
127
  const displayText =
120
128
  type === ContractType.ERC1155
121
129
  ? balance
122
- ? `Owned: ${balance}`
130
+ ? `Owned: ${formatUnits(BigInt(balance), decimals ?? 0)}`
123
131
  : 'ERC-1155'
124
132
  : 'ERC-721';
125
133
 
@@ -1,9 +1,10 @@
1
1
  import { useSelectPaymentModal } from '@0xsequence/kit-checkout';
2
2
  import type { QueryKey } from '@tanstack/react-query';
3
- import type { Hash, Hex } from 'viem';
3
+ import { type Hash, type Hex, zeroAddress } from 'viem';
4
4
  import {
5
5
  type CheckoutOptions,
6
6
  type MarketplaceKind,
7
+ StepType,
7
8
  WalletKind,
8
9
  balanceQueries,
9
10
  collectableKeys,
@@ -92,11 +93,37 @@ export const useBuyCollectable = ({
92
93
  walletType: WalletKind.unknown,
93
94
  });
94
95
 
96
+ const order = await marketplaceClient.getOrders({
97
+ input: [
98
+ {
99
+ orderId: input.orderId,
100
+ contractAddress: collectionAddress,
101
+ marketplace: input.marketplace,
102
+ },
103
+ ],
104
+ });
105
+
95
106
  // these states are necessary to manage appearance of the quantity modal
96
107
  setCheckoutModalLoaded(true);
97
108
  setCheckoutModalIsLoading(false);
98
109
 
99
- const step = steps[0];
110
+ const step = steps.find((step) => step.id === StepType.buy);
111
+
112
+ if (!step) {
113
+ throw new Error('Buy step not found');
114
+ }
115
+
116
+ const feesBps = BigInt(fees.amount);
117
+ let price = String(
118
+ (BigInt(order.orders[0].priceAmount) *
119
+ BigInt(input.quantity) *
120
+ (10000n + feesBps)) /
121
+ 10000n,
122
+ );
123
+
124
+ if (order.orders[0].priceCurrencyAddress !== zeroAddress) {
125
+ price = '0';
126
+ }
100
127
 
101
128
  openSelectPaymentModal({
102
129
  chain: chainId,
@@ -108,7 +135,7 @@ export const useBuyCollectable = ({
108
135
  },
109
136
  ],
110
137
  currencyAddress: priceCurrencyAddress,
111
- price: step.value,
138
+ price,
112
139
  targetContractAddress: step.to,
113
140
  txData: step.data as Hex,
114
141
  collectionAddress,