@0xsequence/marketplace-sdk 0.5.6 → 0.5.7

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 (118) hide show
  1. package/dist/{chunk-J6F5QOW5.js → chunk-3OU7BADC.js} +9 -75
  2. package/dist/chunk-3OU7BADC.js.map +1 -0
  3. package/dist/{chunk-Y75XGZOB.js → chunk-5O3ZAEEX.js} +4 -2
  4. package/dist/chunk-5O3ZAEEX.js.map +1 -0
  5. package/dist/{chunk-4YR6AIXG.js → chunk-G2T7HCWE.js} +5 -7
  6. package/dist/chunk-G2T7HCWE.js.map +1 -0
  7. package/dist/chunk-GFADBQPX.js +2 -0
  8. package/dist/chunk-GFADBQPX.js.map +1 -0
  9. package/dist/{chunk-E2V2BMF6.js → chunk-L2K4DBH2.js} +152 -89
  10. package/dist/chunk-L2K4DBH2.js.map +1 -0
  11. package/dist/{chunk-7C7ADZ2H.js → chunk-OMCWTRBR.js} +9 -42
  12. package/dist/chunk-OMCWTRBR.js.map +1 -0
  13. package/dist/{chunk-7FN62HOP.js → chunk-UMYRZJVY.js} +11 -3
  14. package/dist/chunk-UMYRZJVY.js.map +1 -0
  15. package/dist/{chunk-UZIAX32Y.js → chunk-Y56IIYDF.js} +6 -4
  16. package/dist/{chunk-UZIAX32Y.js.map → chunk-Y56IIYDF.js.map} +1 -1
  17. package/dist/{chunk-AIGFG26L.js → chunk-YA3DWLDC.js} +32 -28
  18. package/dist/chunk-YA3DWLDC.js.map +1 -0
  19. package/dist/{chunk-RIGIV5XT.js → chunk-YYBU45PK.js} +10 -4
  20. package/dist/chunk-YYBU45PK.js.map +1 -0
  21. package/dist/{create-config-CtFGrwXc.d.ts → create-config-CILyA_Hy.d.ts} +1 -1
  22. package/dist/index.css +12 -6
  23. package/dist/index.d.ts +6 -5
  24. package/dist/index.js +13 -10
  25. package/dist/react/_internal/api/index.d.ts +2 -2
  26. package/dist/react/_internal/databeat/index.css.map +1 -1
  27. package/dist/react/_internal/databeat/index.js +7 -7
  28. package/dist/react/_internal/index.d.ts +4 -4
  29. package/dist/react/_internal/index.js +1 -1
  30. package/dist/react/_internal/wagmi/index.d.ts +2 -2
  31. package/dist/react/_internal/wagmi/index.js +1 -1
  32. package/dist/react/hooks/index.css.map +1 -1
  33. package/dist/react/hooks/index.d.ts +8 -15
  34. package/dist/react/hooks/index.js +6 -6
  35. package/dist/react/index.css +12 -6
  36. package/dist/react/index.css.map +1 -1
  37. package/dist/react/index.d.ts +4 -4
  38. package/dist/react/index.js +11 -10
  39. package/dist/react/ssr/index.d.ts +1 -0
  40. package/dist/react/ssr/index.js +10 -2
  41. package/dist/react/ssr/index.js.map +1 -1
  42. package/dist/react/ui/components/collectible-card/index.css +12 -6
  43. package/dist/react/ui/components/collectible-card/index.css.map +1 -1
  44. package/dist/react/ui/components/collectible-card/index.d.ts +2 -2
  45. package/dist/react/ui/components/collectible-card/index.js +11 -10
  46. package/dist/react/ui/icons/index.css.map +1 -1
  47. package/dist/react/ui/index.css +12 -6
  48. package/dist/react/ui/index.css.map +1 -1
  49. package/dist/react/ui/index.d.ts +2 -2
  50. package/dist/react/ui/index.js +11 -10
  51. package/dist/react/ui/modals/_internal/components/actionModal/index.css.map +1 -1
  52. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +2 -2
  53. package/dist/react/ui/modals/_internal/components/actionModal/index.js +7 -7
  54. package/dist/react/ui/styles/index.css.map +1 -1
  55. package/dist/{sdk-config-xWkdBdrL.d.ts → sdk-config-Bs3H_le_.d.ts} +1 -0
  56. package/dist/{services-Cled3TJr.d.ts → services-C3lzi1sL.d.ts} +1 -1
  57. package/dist/styles/index.css +12 -6
  58. package/dist/styles/index.css.map +1 -1
  59. package/dist/styles/index.d.ts +3 -2
  60. package/dist/styles/index.js +4 -2
  61. package/dist/types/index.d.ts +1 -1
  62. package/dist/types/index.js +1 -1
  63. package/dist/{types-C4oGsbnK.d.ts → types-BVD42zE_.d.ts} +1 -1
  64. package/dist/utils/abi/index.js +5 -5
  65. package/dist/utils/index.d.ts +5 -6
  66. package/dist/utils/index.js +9 -9
  67. package/package.json +14 -14
  68. package/src/consts.ts +2 -0
  69. package/src/react/_internal/databeat/index.ts +11 -3
  70. package/src/react/_internal/wagmi/create-config.ts +11 -2
  71. package/src/react/_internal/wallet/__tests__/wallet.test.ts +343 -0
  72. package/src/react/_internal/wallet/useWallet.ts +22 -15
  73. package/src/react/_internal/wallet/wallet.ts +11 -9
  74. package/src/react/hooks/__tests__/useBalanceOfCollectible.test.tsx +6 -14
  75. package/src/react/hooks/__tests__/useCancelOrder.test.tsx +51 -154
  76. package/src/react/hooks/__tests__/useCancelTransactionSteps.test.tsx +21 -19
  77. package/src/react/hooks/__tests__/useCollectionBalanceDetails.test.tsx +5 -14
  78. package/src/react/hooks/__tests__/useCollectionDetailsPolling.test.tsx +5 -10
  79. package/src/react/hooks/__tests__/useCurrencyBalance.test.tsx +69 -80
  80. package/src/react/hooks/__tests__/useGenerateCancelTransaction.test.tsx +12 -67
  81. package/src/react/hooks/__tests__/useGenerateListingTransaction.test.tsx +7 -17
  82. package/src/react/hooks/__tests__/useGenerateOfferTransaction.test.tsx +7 -16
  83. package/src/react/hooks/__tests__/useGenerateSellTransaction.test.tsx +8 -17
  84. package/src/react/hooks/__tests__/useListBalances.test.tsx +3 -8
  85. package/src/react/hooks/__tests__/useListCollectibleActivities.test.tsx +5 -10
  86. package/src/react/hooks/__tests__/useListCollectionActivities.test.tsx +6 -11
  87. package/src/react/hooks/__tests__/useListCollections.test.tsx +5 -13
  88. package/src/react/hooks/__tests__/useMarketplaceConfig.test.tsx +5 -13
  89. package/src/react/hooks/__tests__/useRoyaltyPercentage.test.tsx +46 -78
  90. package/src/react/hooks/options/__mocks__/marketplaceConfig.msw.ts +9 -4
  91. package/src/react/hooks/useCurrencyBalance.tsx +4 -5
  92. package/src/react/hooks/useRoyaltyPercentage.tsx +16 -8
  93. package/src/react/ssr/__tests__/create-ssr-client.test.ts +118 -0
  94. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +25 -6
  95. package/src/react/ui/components/collectible-card/Footer.tsx +46 -7
  96. package/src/react/ui/components/collectible-card/styles.css.ts +26 -2
  97. package/src/react/ui/modals/BuyModal/hooks/__tests__/useCheckoutOptions.test.tsx +10 -28
  98. package/src/react/ui/modals/BuyModal/hooks/__tests__/useLoadData.test.tsx +9 -36
  99. package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +16 -5
  100. package/src/react/ui/modals/CreateListingModal/Modal.tsx +3 -2
  101. package/src/react/ui/modals/SellModal/Modal.tsx +1 -0
  102. package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +8 -7
  103. package/src/types/sdk-config.ts +1 -0
  104. package/src/utils/index.ts +0 -1
  105. package/src/utils/price.ts +11 -0
  106. package/tsconfig.tsbuildinfo +1 -1
  107. package/dist/chunk-4YR6AIXG.js.map +0 -1
  108. package/dist/chunk-7C7ADZ2H.js.map +0 -1
  109. package/dist/chunk-7FN62HOP.js.map +0 -1
  110. package/dist/chunk-AIGFG26L.js.map +0 -1
  111. package/dist/chunk-E2V2BMF6.js.map +0 -1
  112. package/dist/chunk-J6F5QOW5.js.map +0 -1
  113. package/dist/chunk-RIGIV5XT.js.map +0 -1
  114. package/dist/chunk-Y75XGZOB.js.map +0 -1
  115. package/src/react/_internal/test/mocks/publicClient.ts +0 -39
  116. package/src/react/_internal/test/mocks/wagmi.ts +0 -61
  117. package/src/utils/__tests__/get-public-rpc-client.test.ts +0 -111
  118. package/src/utils/get-public-rpc-client.ts +0 -41
@@ -0,0 +1,118 @@
1
+ import { QueryClient } from '@tanstack/react-query';
2
+ import { setupServer } from 'msw/node';
3
+ import {
4
+ afterAll,
5
+ beforeAll,
6
+ beforeEach,
7
+ describe,
8
+ expect,
9
+ it,
10
+ vi,
11
+ } from 'vitest';
12
+ import type { SdkConfig } from '../../../types';
13
+ import { mockConfig } from '../../hooks/options/__mocks__/marketplaceConfig.msw';
14
+ import { createSSRClient } from '../create-ssr-client';
15
+
16
+ const server = setupServer();
17
+
18
+ vi.mock('wagmi', () => ({
19
+ cookieToInitialState: vi.fn().mockReturnValue({
20
+ data: { account: { address: '0x123' } },
21
+ }),
22
+ }));
23
+
24
+ describe('createSSRClient', () => {
25
+ let queryClient: QueryClient;
26
+ let config: SdkConfig;
27
+
28
+ beforeAll(() => {
29
+ // Start MSW server once before all tests
30
+ server.listen({ onUnhandledRequest: 'error' });
31
+ });
32
+
33
+ afterAll(() => {
34
+ // Clean up after all tests are done
35
+ server.close();
36
+ });
37
+
38
+ beforeEach(() => {
39
+ // Reset QueryClient
40
+ queryClient = new QueryClient({
41
+ defaultOptions: {
42
+ queries: {
43
+ retry: false,
44
+ },
45
+ },
46
+ });
47
+
48
+ // Setup basic config
49
+ config = {
50
+ projectId: 'test-project',
51
+ projectAccessKey: 'test-key',
52
+ _internal: {
53
+ builderEnv: 'production',
54
+ },
55
+ };
56
+ });
57
+
58
+ it('should create SSR client with proper methods', () => {
59
+ const client = createSSRClient({
60
+ cookie: 'test-cookie',
61
+ config,
62
+ queryClient,
63
+ });
64
+
65
+ expect(client).toHaveProperty('getInitialState');
66
+ expect(client).toHaveProperty('getMarketplaceConfig');
67
+ expect(client).toHaveProperty('config');
68
+ expect(typeof client.getInitialState).toBe('function');
69
+ expect(typeof client.getMarketplaceConfig).toBe('function');
70
+ });
71
+
72
+ it('should fetch marketplace config successfully', async () => {
73
+ const client = createSSRClient({
74
+ cookie: 'test-cookie',
75
+ config,
76
+ queryClient,
77
+ });
78
+
79
+ const marketplaceConfig = await client.getMarketplaceConfig();
80
+
81
+ expect(marketplaceConfig).toBeDefined();
82
+ expect(marketplaceConfig).toMatchObject({
83
+ publisherId: mockConfig.publisherId,
84
+ title: mockConfig.title,
85
+ collections: expect.arrayContaining([
86
+ expect.objectContaining({
87
+ address: expect.any(String),
88
+ chainId: expect.any(Number),
89
+ }),
90
+ ]),
91
+ });
92
+ });
93
+
94
+ it('should get initial state with wagmi configuration', async () => {
95
+ const client = createSSRClient({
96
+ cookie: 'test-cookie',
97
+ config,
98
+ queryClient,
99
+ });
100
+
101
+ const state = await client.getInitialState();
102
+
103
+ expect(state).toHaveProperty('wagmi');
104
+ expect(state.wagmi).toEqual({
105
+ data: { account: { address: '0x123' } },
106
+ });
107
+ });
108
+
109
+ it('should preserve provided config in the client', () => {
110
+ const client = createSSRClient({
111
+ cookie: 'test-cookie',
112
+ config,
113
+ queryClient,
114
+ });
115
+
116
+ expect(client.config).toEqual(config);
117
+ });
118
+ });
@@ -97,6 +97,7 @@ export function CollectibleCard({
97
97
  const collectibleMetadata = lowestListing?.metadata;
98
98
  const highestOffer = lowestListing?.offer;
99
99
  const [imageLoadingError, setImageLoadingError] = useState(false);
100
+ const [imageLoading, setImageLoading] = useState(true);
100
101
 
101
102
  const { data: lowestListingCurrency } = useCurrency({
102
103
  chainId,
@@ -169,12 +170,30 @@ export function CollectibleCard({
169
170
  />
170
171
  )}
171
172
 
172
- <img
173
- src={imageLoadingError ? ChessTileImage : image || ChessTileImage}
174
- alt={name}
175
- className={collectibleImage}
176
- onError={() => setImageLoadingError(true)}
177
- />
173
+ <Box position="relative">
174
+ {imageLoading && (
175
+ <Skeleton
176
+ position="absolute"
177
+ top="0"
178
+ left="0"
179
+ width="full"
180
+ height="full"
181
+ zIndex="10"
182
+ style={{ borderRadius: 0 }}
183
+ />
184
+ )}
185
+ <img
186
+ src={imageLoadingError ? ChessTileImage : image || ChessTileImage}
187
+ alt={name}
188
+ className={
189
+ imageLoading
190
+ ? collectibleImage.loading
191
+ : collectibleImage.loaded
192
+ }
193
+ onError={() => setImageLoadingError(true)}
194
+ onLoad={() => setImageLoading(false)}
195
+ />
196
+ </Box>
178
197
 
179
198
  <Footer
180
199
  name={name || ''}
@@ -1,15 +1,41 @@
1
- import { Box, IconButton, Image, Text } from '@0xsequence/design-system';
1
+ import {
2
+ Box,
3
+ ChevronLeftIcon,
4
+ ChevronRightIcon,
5
+ IconButton,
6
+ Image,
7
+ Text,
8
+ } from '@0xsequence/design-system';
2
9
  import { formatUnits } from 'viem';
3
10
  import { ContractType, type Currency, type Order } from '../../../_internal';
4
11
  import SvgBellIcon from '../../icons/Bell';
5
- import { footer, offerBellButton } from './styles.css';
12
+ import { footer, footerPriceChevron, offerBellButton } from './styles.css';
6
13
 
7
- const formatPrice = (amount: string, currency: Currency): string => {
14
+ const OVERFLOW_PRICE = 100000000;
15
+ const UNDERFLOW_PRICE = 0.0001;
16
+
17
+ const formatPrice = (amount: string, currency: Currency): React.ReactNode => {
8
18
  const formattedPrice = formatUnits(BigInt(amount), currency.decimals);
9
19
  const numericPrice = Number.parseFloat(formattedPrice);
10
20
 
11
- if (numericPrice < 0.0001) {
12
- return `< 0.0001 ${currency.symbol}`;
21
+ if (numericPrice < UNDERFLOW_PRICE) {
22
+ return (
23
+ <Box display="flex" alignItems="center">
24
+ <ChevronLeftIcon className={footerPriceChevron} />
25
+ <Text>{`${UNDERFLOW_PRICE} ${currency.symbol}`}</Text>
26
+ </Box>
27
+ );
28
+ }
29
+
30
+ if (numericPrice > OVERFLOW_PRICE) {
31
+ return (
32
+ <Box display="flex" alignItems="center">
33
+ <ChevronRightIcon className={footerPriceChevron} />
34
+ <Text>{`${OVERFLOW_PRICE.toLocaleString('en-US', {
35
+ maximumFractionDigits: 2,
36
+ })} ${currency.symbol}`}</Text>
37
+ </Box>
38
+ );
13
39
  }
14
40
 
15
41
  const maxDecimals = numericPrice < 0.01 ? 6 : 4;
@@ -19,7 +45,13 @@ const formatPrice = (amount: string, currency: Currency): string => {
19
45
  maximumFractionDigits: maxDecimals,
20
46
  });
21
47
 
22
- return `${formattedNumber} ${currency.symbol}`;
48
+ return (
49
+ <Box display="flex" alignItems="center" gap="1">
50
+ <Text>
51
+ {formattedNumber} {currency.symbol}
52
+ </Text>
53
+ </Box>
54
+ );
23
55
  };
24
56
 
25
57
  type FooterProps = {
@@ -100,7 +132,14 @@ export const Footer = ({
100
132
 
101
133
  <Box display="flex" alignItems="center" gap="1">
102
134
  {listed && lowestListingCurrency.imageUrl && (
103
- <Image src={lowestListingCurrency.imageUrl} width="3" height="3" />
135
+ <Image
136
+ src={lowestListingCurrency.imageUrl}
137
+ width="3"
138
+ height="3"
139
+ onError={(e) => {
140
+ e.currentTarget.style.display = 'none';
141
+ }}
142
+ />
104
143
  )}
105
144
 
106
145
  <Text
@@ -1,5 +1,5 @@
1
1
  import { atoms } from '@0xsequence/design-system';
2
- import { style } from '@vanilla-extract/css';
2
+ import { style, styleVariants } from '@vanilla-extract/css';
3
3
 
4
4
  export const collectibleCard = style([
5
5
  {
@@ -37,7 +37,7 @@ export const collectibleTileWrapper = style({
37
37
  },
38
38
  });
39
39
 
40
- export const collectibleImage = style({
40
+ const collectibleImageBase = style({
41
41
  width: '175px',
42
42
  height: '175px',
43
43
  objectFit: 'cover',
@@ -49,6 +49,22 @@ export const collectibleImage = style({
49
49
  },
50
50
  });
51
51
 
52
+ export const collectibleImage = styleVariants({
53
+ default: [collectibleImageBase],
54
+ loading: [
55
+ collectibleImageBase,
56
+ {
57
+ visibility: 'hidden',
58
+ },
59
+ ],
60
+ loaded: [
61
+ collectibleImageBase,
62
+ {
63
+ visibility: 'visible',
64
+ },
65
+ ],
66
+ });
67
+
52
68
  export const offerBellButton = style({
53
69
  width: '22px',
54
70
  height: '22px',
@@ -56,6 +72,14 @@ export const offerBellButton = style({
56
72
 
57
73
  export const footer = style([atoms({ background: 'backgroundPrimary' })]);
58
74
 
75
+ export const footerPriceChevron = style([
76
+ atoms({
77
+ width: '3',
78
+ height: '3',
79
+ color: 'text100',
80
+ }),
81
+ ]);
82
+
59
83
  export const actionWrapper = style([
60
84
  atoms({
61
85
  backdropFilter: 'blur',
@@ -1,19 +1,19 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { useCheckoutOptions } from '../useCheckoutOptions';
3
- import { useWallet } from '../../../../../_internal/wallet/useWallet';
4
- import { useFees } from '../useFees';
1
+ import { http, HttpResponse } from 'msw';
2
+ import { zeroAddress } from 'viem';
3
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
5
4
  import { MarketplaceKind } from '../../../../../_internal';
5
+ import { mockMarketplaceEndpoint } from '../../../../../_internal/api/__mocks__/marketplace.msw';
6
+ import { TransactionCrypto } from '../../../../../_internal/api/marketplace.gen';
6
7
  import {
8
+ type RenderHookOptions,
7
9
  renderHook,
8
10
  waitFor,
9
- type RenderHookOptions,
10
11
  } from '../../../../../_internal/test-utils';
11
- import { http, HttpResponse } from 'msw';
12
- import { server } from '../../../../../_internal/test/setup';
13
12
  import { createMockWallet } from '../../../../../_internal/test/mocks/wallet';
14
- import { mockMarketplaceEndpoint } from '../../../../../_internal/api/__mocks__/marketplace.msw';
15
- import { zeroAddress } from 'viem';
16
- import { TransactionCrypto } from '../../../../../_internal/api/marketplace.gen';
13
+ import { server } from '../../../../../_internal/test/setup';
14
+ import { useWallet } from '../../../../../_internal/wallet/useWallet';
15
+ import { useCheckoutOptions } from '../useCheckoutOptions';
16
+ import { useFees } from '../useFees';
17
17
 
18
18
  // Mock dependencies
19
19
  vi.mock('../../../../../_internal/wallet/useWallet');
@@ -47,24 +47,6 @@ describe('useCheckoutOptions', () => {
47
47
  amount: '100000000000000000',
48
48
  receiver: zeroAddress,
49
49
  });
50
-
51
- // Set up default API response
52
- server.use(
53
- http.post(mockMarketplaceEndpoint('CheckoutOptionsMarketplace'), () => {
54
- return HttpResponse.json({
55
- options: {
56
- crypto: TransactionCrypto.all,
57
- swap: [],
58
- nftCheckout: [],
59
- onRamp: [],
60
- },
61
- });
62
- }),
63
- );
64
- });
65
-
66
- afterEach(() => {
67
- server.resetHandlers();
68
50
  });
69
51
 
70
52
  it('should fetch checkout options successfully', async () => {
@@ -1,11 +1,9 @@
1
- import { renderHook } from '@testing-library/react';
2
- import { describe, it, expect, vi, beforeEach } from 'vitest';
3
- import { useLoadData } from '../useLoadData';
4
- import { useCollection, useCollectible } from '../../../../../hooks';
5
- import { useCheckoutOptions } from '../useCheckoutOptions';
1
+ import { describe, expect, it, vi } from 'vitest';
6
2
  import { MarketplaceKind } from '../../../../../_internal';
7
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
8
- import type { ReactNode } from 'react';
3
+ import { renderHook } from '../../../../../_internal/test-utils';
4
+ import { useCollectible, useCollection } from '../../../../../hooks';
5
+ import { useCheckoutOptions } from '../useCheckoutOptions';
6
+ import { useLoadData } from '../useLoadData';
9
7
 
10
8
  // Mock dependencies
11
9
  vi.mock('../../../../../hooks', () => ({
@@ -17,19 +15,6 @@ vi.mock('../useCheckoutOptions', () => ({
17
15
  useCheckoutOptions: vi.fn(),
18
16
  }));
19
17
 
20
- const createWrapper = () => {
21
- const queryClient = new QueryClient({
22
- defaultOptions: {
23
- queries: {
24
- retry: false,
25
- },
26
- },
27
- });
28
- return ({ children }: { children: ReactNode }) => (
29
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
30
- );
31
- };
32
-
33
18
  describe('useLoadData', () => {
34
19
  const defaultProps = {
35
20
  chainId: 1,
@@ -39,10 +24,6 @@ describe('useLoadData', () => {
39
24
  marketplace: MarketplaceKind.sequence_marketplace_v2,
40
25
  };
41
26
 
42
- beforeEach(() => {
43
- vi.clearAllMocks();
44
- });
45
-
46
27
  it('should return loading state when any data is loading', () => {
47
28
  // Mock one hook to be loading
48
29
  (useCollection as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
@@ -65,9 +46,7 @@ describe('useLoadData', () => {
65
46
  },
66
47
  );
67
48
 
68
- const { result } = renderHook(() => useLoadData(defaultProps), {
69
- wrapper: createWrapper(),
70
- });
49
+ const { result } = renderHook(() => useLoadData(defaultProps));
71
50
 
72
51
  expect(result.current.isLoading).toBe(true);
73
52
  expect(result.current.isError).toBe(false);
@@ -98,9 +77,7 @@ describe('useLoadData', () => {
98
77
  },
99
78
  );
100
79
 
101
- const { result } = renderHook(() => useLoadData(defaultProps), {
102
- wrapper: createWrapper(),
103
- });
80
+ const { result } = renderHook(() => useLoadData(defaultProps));
104
81
 
105
82
  expect(result.current.isError).toBe(true);
106
83
  expect(result.current.isLoading).toBe(false);
@@ -136,9 +113,7 @@ describe('useLoadData', () => {
136
113
  },
137
114
  );
138
115
 
139
- const { result } = renderHook(() => useLoadData(defaultProps), {
140
- wrapper: createWrapper(),
141
- });
116
+ const { result } = renderHook(() => useLoadData(defaultProps));
142
117
 
143
118
  expect(result.current.isLoading).toBe(false);
144
119
  expect(result.current.isError).toBe(false);
@@ -174,9 +149,7 @@ describe('useLoadData', () => {
174
149
  },
175
150
  );
176
151
 
177
- const { result } = renderHook(() => useLoadData(defaultProps), {
178
- wrapper: createWrapper(),
179
- });
152
+ const { result } = renderHook(() => useLoadData(defaultProps));
180
153
 
181
154
  // Should be loading if any data is loading
182
155
  expect(result.current.isLoading).toBe(true);
@@ -1,8 +1,13 @@
1
1
  import { Box, Text, TokenImage } from '@0xsequence/design-system';
2
2
  import { observer } from '@legendapp/state/react';
3
3
  import type { Hex } from 'viem';
4
- import { formatUnits, parseUnits } from 'viem';
5
- import { useCurrency } from '../../../../hooks';
4
+ import { parseUnits } from 'viem';
5
+ import {
6
+ DEFAULT_MARKETPLACE_FEE_PERCENTAGE,
7
+ compareAddress,
8
+ formatPrice,
9
+ } from '../../../../..';
10
+ import { useCurrency, useMarketplaceConfig } from '../../../../hooks';
6
11
  import { ActionModal } from '../../_internal/components/actionModal';
7
12
  import QuantityInput from '../../_internal/components/quantityInput';
8
13
  import { buyModal$ } from '../store';
@@ -16,14 +21,20 @@ interface ERC1155QuantityModalProps extends CheckoutModalProps {
16
21
 
17
22
  export const ERC1155QuantityModal = observer(
18
23
  ({ buy, collectable, order }: ERC1155QuantityModalProps) => {
24
+ const { data: marketplaceConfig } = useMarketplaceConfig();
19
25
  const { data: currency, isLoading: isCurrencyLoading } = useCurrency({
20
26
  chainId: order.chainId,
21
27
  currencyAddress: order.priceCurrencyAddress,
22
28
  });
23
-
24
29
  const quantity = Number(buyModal$.state.quantity.get());
25
30
  const pricePerToken = order.priceAmount;
26
- const totalPrice = (BigInt(quantity) * BigInt(pricePerToken)).toString();
31
+ const marketplaceFeePercentage =
32
+ marketplaceConfig?.collections.find((collection) =>
33
+ compareAddress(collection.address, order.collectionContractAddress),
34
+ )?.feePercentage || DEFAULT_MARKETPLACE_FEE_PERCENTAGE;
35
+ const price = Number(quantity) * Number(pricePerToken);
36
+ const totalPrice =
37
+ price + (price * Number(marketplaceFeePercentage || 0)) / 100;
27
38
 
28
39
  if (
29
40
  buyModal$.state.checkoutModalLoaded.get() &&
@@ -92,7 +103,7 @@ export const ERC1155QuantityModal = observer(
92
103
  fontWeight="bold"
93
104
  fontFamily="body"
94
105
  >
95
- {formatUnits(BigInt(totalPrice), currency.decimals || 0)}
106
+ {formatPrice(totalPrice, currency.decimals)}
96
107
  </Text>
97
108
 
98
109
  <Text color="text80" fontSize="small" fontFamily="body">
@@ -2,6 +2,7 @@ import { Box } from '@0xsequence/design-system';
2
2
  import { Show, observer } from '@legendapp/state/react';
3
3
  import { parseUnits } from 'viem';
4
4
  import { useAccount } from 'wagmi';
5
+ import { dateToUnixTime } from '../../../../utils/date';
5
6
  import type { ContractType } from '../../../_internal';
6
7
  import {
7
8
  useBalanceOfCollectible,
@@ -21,9 +22,8 @@ import PriceInput from '../_internal/components/priceInput';
21
22
  import QuantityInput from '../_internal/components/quantityInput';
22
23
  import TokenPreview from '../_internal/components/tokenPreview';
23
24
  import TransactionDetails from '../_internal/components/transactionDetails';
24
- import { createListingModal$ } from './store';
25
- import { dateToUnixTime } from '../../../../utils/date';
26
25
  import { useCreateListing } from './hooks/useCreateListing';
26
+ import { createListingModal$ } from './store';
27
27
 
28
28
  export const CreateListingModal = () => {
29
29
  return <Show if={createListingModal$.isOpen}>{() => <Modal />}</Show>;
@@ -211,6 +211,7 @@ const Modal = observer(() => {
211
211
  chainId={chainId}
212
212
  price={createListingModal$.listingPrice.get()}
213
213
  currencyImageUrl={listingPrice.currency.imageUrl}
214
+ includeMarketplaceFee={false}
214
215
  />
215
216
  </ActionModal>
216
217
  );
@@ -133,6 +133,7 @@ const Modal = observer(() => {
133
133
  collectibleId={tokenId}
134
134
  collectionAddress={collectionAddress}
135
135
  chainId={chainId}
136
+ includeMarketplaceFee={true}
136
137
  price={
137
138
  currency
138
139
  ? {
@@ -1,5 +1,6 @@
1
1
  import { Box, Image, Skeleton, Text } from '@0xsequence/design-system';
2
2
  import { type Hex, formatUnits } from 'viem';
3
+ import { DEFAULT_MARKETPLACE_FEE_PERCENTAGE } from '../../../../../../consts';
3
4
  import type { Price } from '../../../../../../types';
4
5
  import {
5
6
  useMarketplaceConfig,
@@ -12,27 +13,27 @@ type TransactionDetailsProps = {
12
13
  chainId: string;
13
14
  price?: Price;
14
15
  currencyImageUrl?: string;
16
+ includeMarketplaceFee: boolean;
15
17
  // We use a placeholder price for create listing modal
16
18
  showPlaceholderPrice?: boolean;
17
19
  };
18
20
 
19
- //TODO: Move this
20
- const DEFAULT_MARKETPLACE_FEE_PERCENTAGE = 2.5;
21
-
22
21
  export default function TransactionDetails({
23
22
  collectibleId,
24
23
  collectionAddress,
25
24
  chainId,
25
+ includeMarketplaceFee,
26
26
  price,
27
27
  showPlaceholderPrice,
28
28
  currencyImageUrl,
29
29
  }: TransactionDetailsProps) {
30
30
  const { data, isLoading: marketplaceConfigLoading } = useMarketplaceConfig();
31
31
 
32
- const marketplaceFeePercentage =
33
- data?.collections.find(
34
- (collection) => collection.address === collectionAddress,
35
- )?.feePercentage || DEFAULT_MARKETPLACE_FEE_PERCENTAGE;
32
+ const marketplaceFeePercentage = includeMarketplaceFee
33
+ ? data?.collections.find(
34
+ (collection) => collection.address === collectionAddress,
35
+ )?.feePercentage || DEFAULT_MARKETPLACE_FEE_PERCENTAGE
36
+ : 0;
36
37
  const { data: royaltyPercentage, isLoading: royaltyPercentageLoading } =
37
38
  useRoyaltyPercentage({
38
39
  chainId,
@@ -17,6 +17,7 @@ export type SdkConfig = {
17
17
  nextAccessKey?: string;
18
18
  builderEnv?: Env;
19
19
  marketplaceEnv?: Env;
20
+ nodeGatewayEnv?: Env;
20
21
  metadataEnv?: Env;
21
22
  indexerEnv?: Env;
22
23
  };
@@ -1,6 +1,5 @@
1
1
  export * from './abi';
2
2
  export * from './address';
3
- export * from './get-public-rpc-client';
4
3
  export * from './network';
5
4
  export * from './price';
6
5
  export * from './getMarketplaceDetails';
@@ -18,3 +18,14 @@ export const calculatePriceDifferencePercentage = ({
18
18
 
19
19
  return percentageDifference.toFixed(2);
20
20
  };
21
+
22
+ export const formatPrice = (
23
+ amount: string | number | bigint,
24
+ decimals: number,
25
+ ): string => {
26
+ const formattedUnits = Number(formatUnits(BigInt(amount), decimals));
27
+ return formattedUnits.toLocaleString('en-US', {
28
+ minimumFractionDigits: 0,
29
+ maximumFractionDigits: decimals,
30
+ });
31
+ };