@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.
- package/dist/{chunk-J6F5QOW5.js → chunk-3OU7BADC.js} +9 -75
- package/dist/chunk-3OU7BADC.js.map +1 -0
- package/dist/{chunk-Y75XGZOB.js → chunk-5O3ZAEEX.js} +4 -2
- package/dist/chunk-5O3ZAEEX.js.map +1 -0
- package/dist/{chunk-4YR6AIXG.js → chunk-G2T7HCWE.js} +5 -7
- package/dist/chunk-G2T7HCWE.js.map +1 -0
- package/dist/chunk-GFADBQPX.js +2 -0
- package/dist/chunk-GFADBQPX.js.map +1 -0
- package/dist/{chunk-E2V2BMF6.js → chunk-L2K4DBH2.js} +152 -89
- package/dist/chunk-L2K4DBH2.js.map +1 -0
- package/dist/{chunk-7C7ADZ2H.js → chunk-OMCWTRBR.js} +9 -42
- package/dist/chunk-OMCWTRBR.js.map +1 -0
- package/dist/{chunk-7FN62HOP.js → chunk-UMYRZJVY.js} +11 -3
- package/dist/chunk-UMYRZJVY.js.map +1 -0
- package/dist/{chunk-UZIAX32Y.js → chunk-Y56IIYDF.js} +6 -4
- package/dist/{chunk-UZIAX32Y.js.map → chunk-Y56IIYDF.js.map} +1 -1
- package/dist/{chunk-AIGFG26L.js → chunk-YA3DWLDC.js} +32 -28
- package/dist/chunk-YA3DWLDC.js.map +1 -0
- package/dist/{chunk-RIGIV5XT.js → chunk-YYBU45PK.js} +10 -4
- package/dist/chunk-YYBU45PK.js.map +1 -0
- package/dist/{create-config-CtFGrwXc.d.ts → create-config-CILyA_Hy.d.ts} +1 -1
- package/dist/index.css +12 -6
- package/dist/index.d.ts +6 -5
- package/dist/index.js +13 -10
- package/dist/react/_internal/api/index.d.ts +2 -2
- package/dist/react/_internal/databeat/index.css.map +1 -1
- package/dist/react/_internal/databeat/index.js +7 -7
- package/dist/react/_internal/index.d.ts +4 -4
- package/dist/react/_internal/index.js +1 -1
- package/dist/react/_internal/wagmi/index.d.ts +2 -2
- package/dist/react/_internal/wagmi/index.js +1 -1
- package/dist/react/hooks/index.css.map +1 -1
- package/dist/react/hooks/index.d.ts +8 -15
- package/dist/react/hooks/index.js +6 -6
- package/dist/react/index.css +12 -6
- package/dist/react/index.css.map +1 -1
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +11 -10
- package/dist/react/ssr/index.d.ts +1 -0
- package/dist/react/ssr/index.js +10 -2
- package/dist/react/ssr/index.js.map +1 -1
- package/dist/react/ui/components/collectible-card/index.css +12 -6
- package/dist/react/ui/components/collectible-card/index.css.map +1 -1
- package/dist/react/ui/components/collectible-card/index.d.ts +2 -2
- package/dist/react/ui/components/collectible-card/index.js +11 -10
- package/dist/react/ui/icons/index.css.map +1 -1
- package/dist/react/ui/index.css +12 -6
- package/dist/react/ui/index.css.map +1 -1
- package/dist/react/ui/index.d.ts +2 -2
- package/dist/react/ui/index.js +11 -10
- package/dist/react/ui/modals/_internal/components/actionModal/index.css.map +1 -1
- package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +2 -2
- package/dist/react/ui/modals/_internal/components/actionModal/index.js +7 -7
- package/dist/react/ui/styles/index.css.map +1 -1
- package/dist/{sdk-config-xWkdBdrL.d.ts → sdk-config-Bs3H_le_.d.ts} +1 -0
- package/dist/{services-Cled3TJr.d.ts → services-C3lzi1sL.d.ts} +1 -1
- package/dist/styles/index.css +12 -6
- package/dist/styles/index.css.map +1 -1
- package/dist/styles/index.d.ts +3 -2
- package/dist/styles/index.js +4 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -1
- package/dist/{types-C4oGsbnK.d.ts → types-BVD42zE_.d.ts} +1 -1
- package/dist/utils/abi/index.js +5 -5
- package/dist/utils/index.d.ts +5 -6
- package/dist/utils/index.js +9 -9
- package/package.json +14 -14
- package/src/consts.ts +2 -0
- package/src/react/_internal/databeat/index.ts +11 -3
- package/src/react/_internal/wagmi/create-config.ts +11 -2
- package/src/react/_internal/wallet/__tests__/wallet.test.ts +343 -0
- package/src/react/_internal/wallet/useWallet.ts +22 -15
- package/src/react/_internal/wallet/wallet.ts +11 -9
- package/src/react/hooks/__tests__/useBalanceOfCollectible.test.tsx +6 -14
- package/src/react/hooks/__tests__/useCancelOrder.test.tsx +51 -154
- package/src/react/hooks/__tests__/useCancelTransactionSteps.test.tsx +21 -19
- package/src/react/hooks/__tests__/useCollectionBalanceDetails.test.tsx +5 -14
- package/src/react/hooks/__tests__/useCollectionDetailsPolling.test.tsx +5 -10
- package/src/react/hooks/__tests__/useCurrencyBalance.test.tsx +69 -80
- package/src/react/hooks/__tests__/useGenerateCancelTransaction.test.tsx +12 -67
- package/src/react/hooks/__tests__/useGenerateListingTransaction.test.tsx +7 -17
- package/src/react/hooks/__tests__/useGenerateOfferTransaction.test.tsx +7 -16
- package/src/react/hooks/__tests__/useGenerateSellTransaction.test.tsx +8 -17
- package/src/react/hooks/__tests__/useListBalances.test.tsx +3 -8
- package/src/react/hooks/__tests__/useListCollectibleActivities.test.tsx +5 -10
- package/src/react/hooks/__tests__/useListCollectionActivities.test.tsx +6 -11
- package/src/react/hooks/__tests__/useListCollections.test.tsx +5 -13
- package/src/react/hooks/__tests__/useMarketplaceConfig.test.tsx +5 -13
- package/src/react/hooks/__tests__/useRoyaltyPercentage.test.tsx +46 -78
- package/src/react/hooks/options/__mocks__/marketplaceConfig.msw.ts +9 -4
- package/src/react/hooks/useCurrencyBalance.tsx +4 -5
- package/src/react/hooks/useRoyaltyPercentage.tsx +16 -8
- package/src/react/ssr/__tests__/create-ssr-client.test.ts +118 -0
- package/src/react/ui/components/collectible-card/CollectibleCard.tsx +25 -6
- package/src/react/ui/components/collectible-card/Footer.tsx +46 -7
- package/src/react/ui/components/collectible-card/styles.css.ts +26 -2
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useCheckoutOptions.test.tsx +10 -28
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useLoadData.test.tsx +9 -36
- package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +16 -5
- package/src/react/ui/modals/CreateListingModal/Modal.tsx +3 -2
- package/src/react/ui/modals/SellModal/Modal.tsx +1 -0
- package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +8 -7
- package/src/types/sdk-config.ts +1 -0
- package/src/utils/index.ts +0 -1
- package/src/utils/price.ts +11 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/chunk-4YR6AIXG.js.map +0 -1
- package/dist/chunk-7C7ADZ2H.js.map +0 -1
- package/dist/chunk-7FN62HOP.js.map +0 -1
- package/dist/chunk-AIGFG26L.js.map +0 -1
- package/dist/chunk-E2V2BMF6.js.map +0 -1
- package/dist/chunk-J6F5QOW5.js.map +0 -1
- package/dist/chunk-RIGIV5XT.js.map +0 -1
- package/dist/chunk-Y75XGZOB.js.map +0 -1
- package/src/react/_internal/test/mocks/publicClient.ts +0 -39
- package/src/react/_internal/test/mocks/wagmi.ts +0 -61
- package/src/utils/__tests__/get-public-rpc-client.test.ts +0 -111
- 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
|
-
<
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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 {
|
|
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
|
|
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 <
|
|
12
|
-
return
|
|
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
|
|
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
|
|
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
|
-
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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 {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
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 {
|
|
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 {
|
|
8
|
-
import
|
|
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 {
|
|
5
|
-
import {
|
|
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
|
|
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
|
-
{
|
|
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
|
);
|
|
@@ -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
|
-
|
|
35
|
-
|
|
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,
|
package/src/types/sdk-config.ts
CHANGED
package/src/utils/index.ts
CHANGED
package/src/utils/price.ts
CHANGED
|
@@ -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
|
+
};
|