@0xsequence/marketplace-sdk 0.8.2 → 0.8.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.
- package/CHANGELOG.md +15 -0
- package/dist/{builder-types-Wrqq6YoW.d.ts → builder-types-BY6eD6vD.d.ts} +1 -1
- package/dist/{chunk-IZ44XPBH.js → chunk-25CAMYCG.js} +2 -2
- package/dist/{chunk-LDHGFXPJ.js → chunk-44YGZVBS.js} +2 -2
- package/dist/{chunk-BNAUZXPV.js → chunk-ALICO7NG.js} +3 -3
- package/dist/chunk-ALICO7NG.js.map +1 -0
- package/dist/{chunk-3II5GLHE.js → chunk-HGKWWZWY.js} +2 -2
- package/dist/{chunk-S2UFNIYX.js → chunk-HRL2TMXU.js} +12 -9
- package/dist/chunk-HRL2TMXU.js.map +1 -0
- package/dist/{chunk-XOHAZXBZ.js → chunk-VBRJ2OPM.js} +14 -6
- package/dist/chunk-VBRJ2OPM.js.map +1 -0
- package/dist/{chunk-F6CUGMI4.js → chunk-VF3LWBQB.js} +378 -263
- package/dist/chunk-VF3LWBQB.js.map +1 -0
- package/dist/{chunk-GBQVYNCD.js → chunk-XUNDLCEH.js} +3 -3
- package/dist/{chunk-4DFOSZTE.js → chunk-ZSCZLHKX.js} +195 -3
- package/dist/chunk-ZSCZLHKX.js.map +1 -0
- package/dist/{create-config-B58hoCDv.d.ts → create-config-qDML4ZNn.d.ts} +1 -1
- package/dist/{index-PhhCRKUH.d.ts → index-DtWR0b_l.d.ts} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -9
- package/dist/{lowestListing-CuLxIWxy.d.ts → lowestListing-W7P4EkC3.d.ts} +34 -11
- package/dist/{marketplace.gen-De2-sxiG.d.ts → marketplace.gen-DS-MmGEB.d.ts} +35 -4
- package/dist/react/_internal/api/index.d.ts +2 -2
- package/dist/react/_internal/api/index.js +1 -1
- package/dist/react/_internal/databeat/index.d.ts +1 -1
- package/dist/react/_internal/databeat/index.js +8 -8
- package/dist/react/_internal/index.d.ts +5 -5
- package/dist/react/_internal/index.js +2 -2
- package/dist/react/_internal/wagmi/index.d.ts +3 -3
- package/dist/react/_internal/wagmi/index.js +2 -2
- package/dist/react/hooks/index.d.ts +72 -49
- package/dist/react/hooks/index.js +9 -7
- package/dist/react/hooks/options/index.d.ts +3 -3
- package/dist/react/hooks/options/index.js +4 -4
- package/dist/react/index.d.ts +8 -8
- package/dist/react/index.js +12 -10
- package/dist/react/queries/index.d.ts +2 -2
- package/dist/react/queries/index.js +7 -3
- package/dist/react/ssr/index.d.ts +2 -2
- package/dist/react/ssr/index.js +3 -3
- package/dist/react/ui/components/collectible-card/index.d.ts +1 -1
- package/dist/react/ui/components/collectible-card/index.js +10 -10
- package/dist/react/ui/icons/index.js +3 -3
- package/dist/react/ui/index.d.ts +1 -1
- package/dist/react/ui/index.js +10 -10
- package/dist/react/ui/modals/_internal/components/actionModal/index.js +8 -8
- package/dist/{services-BdzIAR9w.d.ts → services-BOX67E7W.d.ts} +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js +2 -4
- package/dist/{types-CmHOStH3.d.ts → types-CJLhc2VZ.d.ts} +2 -2
- package/dist/utils/abi/index.js +5 -5
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +7 -7
- package/package.json +1 -1
- package/src/react/_internal/api/__mocks__/marketplace.msw.ts +35 -18
- package/src/react/_internal/api/marketplace.gen.ts +39 -6
- package/src/react/_internal/api/zod-schema.ts +7 -18
- package/src/react/hooks/__tests__/useCancelTransactionSteps.test.tsx +4 -9
- package/src/react/hooks/__tests__/useGenerateCancelTransaction.test.tsx +5 -4
- package/src/react/hooks/__tests__/useGenerateListingTransaction.test.tsx +14 -2
- package/src/react/hooks/__tests__/useGenerateOfferTransaction.test.tsx +115 -57
- package/src/react/hooks/__tests__/useGenerateSellTransaction.test.tsx +10 -3
- package/src/react/hooks/__tests__/useInventory.test.tsx +294 -0
- package/src/react/hooks/index.ts +1 -0
- package/src/react/hooks/useAutoSelectFeeOption.tsx +10 -3
- package/src/react/hooks/useCancelOrder.tsx +1 -0
- package/src/react/hooks/useCancelTransactionSteps.tsx +20 -6
- package/src/react/hooks/useGenerateOfferTransaction.tsx +11 -1
- package/src/react/hooks/useInventory.tsx +15 -0
- package/src/react/hooks/util/optimisticCancelUpdates.ts +115 -0
- package/src/react/queries/index.ts +1 -0
- package/src/react/queries/inventory.ts +303 -0
- package/src/react/queries/listBalances.ts +1 -8
- package/src/react/queries/listCollectibles.ts +12 -3
- package/src/react/ui/modals/CreateListingModal/__tests__/Modal.test.tsx +74 -104
- package/src/react/ui/modals/CreateListingModal/hooks/useTransactionSteps.tsx +2 -2
- package/src/react/ui/modals/MakeOfferModal/__tests__/Modal.test.tsx +108 -78
- package/src/react/ui/modals/MakeOfferModal/hooks/useTransactionSteps.tsx +2 -2
- package/src/react/ui/modals/SellModal/hooks/useTransactionSteps.tsx +2 -2
- package/src/react/ui/modals/_internal/components/actionModal/ActionModal.test.tsx +286 -0
- package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +16 -4
- package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +35 -132
- package/src/react/ui/modals/_internal/components/floorPriceText/__tests__/FloorPriceText.test.tsx +199 -0
- package/src/react/ui/modals/_internal/components/priceInput/__tests__/PriceInput.test.tsx +55 -0
- package/src/react/ui/modals/_internal/components/priceInput/index.tsx +1 -1
- package/src/react/ui/modals/_internal/components/switchChainModal/index.tsx +2 -2
- package/src/types/api-types.ts +0 -1
- package/test/const.ts +24 -0
- package/test/test-utils.tsx +74 -26
- package/.changeset/flat-parks-clean.md +0 -8
- package/.changeset/seven-doors-taste.md +0 -5
- package/dist/chunk-4DFOSZTE.js.map +0 -1
- package/dist/chunk-BNAUZXPV.js.map +0 -1
- package/dist/chunk-F6CUGMI4.js.map +0 -1
- package/dist/chunk-S2UFNIYX.js.map +0 -1
- package/dist/chunk-XOHAZXBZ.js.map +0 -1
- package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +0 -164
- /package/dist/{chunk-IZ44XPBH.js.map → chunk-25CAMYCG.js.map} +0 -0
- /package/dist/{chunk-LDHGFXPJ.js.map → chunk-44YGZVBS.js.map} +0 -0
- /package/dist/{chunk-3II5GLHE.js.map → chunk-HGKWWZWY.js.map} +0 -0
- /package/dist/{chunk-GBQVYNCD.js.map → chunk-XUNDLCEH.js.map} +0 -0
|
@@ -50,12 +50,18 @@ describe('useGenerateListingTransaction', () => {
|
|
|
50
50
|
[
|
|
51
51
|
{
|
|
52
52
|
"data": "0x...",
|
|
53
|
-
"executeType": "order",
|
|
54
53
|
"id": "tokenApproval",
|
|
55
54
|
"price": "0",
|
|
56
55
|
"to": "0x1234567890123456789012345678901234567890",
|
|
57
56
|
"value": "0",
|
|
58
57
|
},
|
|
58
|
+
{
|
|
59
|
+
"data": "0x...",
|
|
60
|
+
"id": "createListing",
|
|
61
|
+
"price": "0",
|
|
62
|
+
"to": "0x1234567890123456789012345678901234567890",
|
|
63
|
+
"value": "0",
|
|
64
|
+
},
|
|
59
65
|
],
|
|
60
66
|
{
|
|
61
67
|
"collectionAddress": "0x0000000000000000000000000000000000000000",
|
|
@@ -91,12 +97,18 @@ describe('useGenerateListingTransaction', () => {
|
|
|
91
97
|
[
|
|
92
98
|
{
|
|
93
99
|
"data": "0x...",
|
|
94
|
-
"executeType": "order",
|
|
95
100
|
"id": "tokenApproval",
|
|
96
101
|
"price": "0",
|
|
97
102
|
"to": "0x1234567890123456789012345678901234567890",
|
|
98
103
|
"value": "0",
|
|
99
104
|
},
|
|
105
|
+
{
|
|
106
|
+
"data": "0x...",
|
|
107
|
+
"id": "createListing",
|
|
108
|
+
"price": "0",
|
|
109
|
+
"to": "0x1234567890123456789012345678901234567890",
|
|
110
|
+
"value": "0",
|
|
111
|
+
},
|
|
100
112
|
],
|
|
101
113
|
{
|
|
102
114
|
"collectionAddress": "0x0000000000000000000000000000000000000000",
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { renderHook, server, waitFor } from '@test';
|
|
2
|
+
import { createMockWallet } from '@test/mocks/wallet';
|
|
2
3
|
import { http, HttpResponse } from 'msw';
|
|
3
4
|
import { zeroAddress } from 'viem';
|
|
4
5
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
createMockSteps,
|
|
8
|
+
mockMarketplaceEndpoint,
|
|
9
|
+
} from '../../_internal/api/__mocks__/marketplace.msw';
|
|
6
10
|
import {
|
|
7
11
|
ContractType,
|
|
8
12
|
OrderbookKind,
|
|
13
|
+
StepType,
|
|
14
|
+
WalletKind,
|
|
9
15
|
} from '../../_internal/api/marketplace.gen';
|
|
16
|
+
import * as walletModule from '../../_internal/wallet/useWallet';
|
|
10
17
|
import { useGenerateOfferTransaction } from '../useGenerateOfferTransaction';
|
|
11
18
|
|
|
12
19
|
describe('useGenerateOfferTransaction', () => {
|
|
@@ -44,34 +51,9 @@ describe('useGenerateOfferTransaction', () => {
|
|
|
44
51
|
|
|
45
52
|
await result.current.generateOfferTransactionAsync(mockTransactionProps);
|
|
46
53
|
|
|
47
|
-
expect(mockOnSuccess
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
{
|
|
51
|
-
"data": "0x...",
|
|
52
|
-
"executeType": "order",
|
|
53
|
-
"id": "tokenApproval",
|
|
54
|
-
"price": "0",
|
|
55
|
-
"to": "0x1234567890123456789012345678901234567890",
|
|
56
|
-
"value": "0",
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
{
|
|
60
|
-
"collectionAddress": "0x0000000000000000000000000000000000000000",
|
|
61
|
-
"contractType": "ERC721",
|
|
62
|
-
"maker": "0x0000000000000000000000000000000000000000",
|
|
63
|
-
"offer": {
|
|
64
|
-
"currencyAddress": "0x0000000000000000000000000000000000000000",
|
|
65
|
-
"expiry": 2024-12-31T00:00:00.000Z,
|
|
66
|
-
"pricePerToken": "1000000000000000000",
|
|
67
|
-
"quantity": "1",
|
|
68
|
-
"tokenId": "1",
|
|
69
|
-
},
|
|
70
|
-
"orderbook": "sequence_marketplace_v2",
|
|
71
|
-
},
|
|
72
|
-
undefined,
|
|
73
|
-
]
|
|
74
|
-
`);
|
|
54
|
+
expect(mockOnSuccess).toHaveBeenCalled();
|
|
55
|
+
const steps = mockOnSuccess.mock.calls[0]?.[0];
|
|
56
|
+
expect(steps.length).toBeGreaterThan(0);
|
|
75
57
|
});
|
|
76
58
|
|
|
77
59
|
it('should handle non-async generation with callback', async () => {
|
|
@@ -84,34 +66,9 @@ describe('useGenerateOfferTransaction', () => {
|
|
|
84
66
|
await waitFor(() => {
|
|
85
67
|
expect(mockOnSuccess).toHaveBeenCalled();
|
|
86
68
|
});
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
{
|
|
91
|
-
"data": "0x...",
|
|
92
|
-
"executeType": "order",
|
|
93
|
-
"id": "tokenApproval",
|
|
94
|
-
"price": "0",
|
|
95
|
-
"to": "0x1234567890123456789012345678901234567890",
|
|
96
|
-
"value": "0",
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
{
|
|
100
|
-
"collectionAddress": "0x0000000000000000000000000000000000000000",
|
|
101
|
-
"contractType": "ERC721",
|
|
102
|
-
"maker": "0x0000000000000000000000000000000000000000",
|
|
103
|
-
"offer": {
|
|
104
|
-
"currencyAddress": "0x0000000000000000000000000000000000000000",
|
|
105
|
-
"expiry": 2024-12-31T00:00:00.000Z,
|
|
106
|
-
"pricePerToken": "1000000000000000000",
|
|
107
|
-
"quantity": "1",
|
|
108
|
-
"tokenId": "1",
|
|
109
|
-
},
|
|
110
|
-
"orderbook": "sequence_marketplace_v2",
|
|
111
|
-
},
|
|
112
|
-
undefined,
|
|
113
|
-
]
|
|
114
|
-
`);
|
|
69
|
+
|
|
70
|
+
const steps = mockOnSuccess.mock.calls[0]?.[0];
|
|
71
|
+
expect(steps.length).toBeGreaterThan(0);
|
|
115
72
|
});
|
|
116
73
|
|
|
117
74
|
it('should handle API errors', async () => {
|
|
@@ -158,4 +115,105 @@ describe('useGenerateOfferTransaction', () => {
|
|
|
158
115
|
|
|
159
116
|
expect(mockOnSuccess).not.toHaveBeenCalled();
|
|
160
117
|
});
|
|
118
|
+
|
|
119
|
+
describe('wallet-specific behavior', () => {
|
|
120
|
+
// Create mock wallets for different types
|
|
121
|
+
const mockSequenceWallet = createMockWallet({
|
|
122
|
+
walletKind: WalletKind.sequence,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const mockNonSequenceWallet = createMockWallet({
|
|
126
|
+
walletKind: WalletKind.unknown,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should not include tokenApproval step for Sequence wallet', async () => {
|
|
130
|
+
// Mock useWallet to return a Sequence wallet
|
|
131
|
+
const useWalletSpy = vi.spyOn(walletModule, 'useWallet');
|
|
132
|
+
useWalletSpy.mockReturnValue({
|
|
133
|
+
wallet: mockSequenceWallet,
|
|
134
|
+
isLoading: false,
|
|
135
|
+
isError: false,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Override the default handler to include walletKind in the response
|
|
139
|
+
server.use(
|
|
140
|
+
http.post(
|
|
141
|
+
mockMarketplaceEndpoint('GenerateOfferTransaction'),
|
|
142
|
+
async ({ request }) => {
|
|
143
|
+
// Add wallet type to the request payload
|
|
144
|
+
const reqBody = (await request.json()) as Record<string, unknown>;
|
|
145
|
+
reqBody.walletType = WalletKind.sequence;
|
|
146
|
+
|
|
147
|
+
// For Sequence wallet - only return createOffer step
|
|
148
|
+
return HttpResponse.json({
|
|
149
|
+
steps: createMockSteps([StepType.createOffer]),
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
),
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const { result } = renderHook(() =>
|
|
156
|
+
useGenerateOfferTransaction(defaultArgs),
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
await result.current.generateOfferTransactionAsync(mockTransactionProps);
|
|
160
|
+
|
|
161
|
+
expect(mockOnSuccess).toHaveBeenCalled();
|
|
162
|
+
const steps = mockOnSuccess.mock.calls[0]?.[0];
|
|
163
|
+
|
|
164
|
+
// Verify there is only one step: createOffer (no tokenApproval)
|
|
165
|
+
expect(steps).toHaveLength(1);
|
|
166
|
+
expect(steps[0].id).toBe('createOffer');
|
|
167
|
+
|
|
168
|
+
// Restore the original useWallet implementation
|
|
169
|
+
useWalletSpy.mockRestore();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should include tokenApproval step for non-Sequence wallet', async () => {
|
|
173
|
+
// Mock useWallet to return a non-Sequence wallet
|
|
174
|
+
const useWalletSpy = vi.spyOn(walletModule, 'useWallet');
|
|
175
|
+
useWalletSpy.mockReturnValue({
|
|
176
|
+
wallet: mockNonSequenceWallet,
|
|
177
|
+
isLoading: false,
|
|
178
|
+
isError: false,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Override the default handler to include walletKind in the response
|
|
182
|
+
server.use(
|
|
183
|
+
http.post(
|
|
184
|
+
mockMarketplaceEndpoint('GenerateOfferTransaction'),
|
|
185
|
+
async ({ request }) => {
|
|
186
|
+
// Add wallet type to the request payload
|
|
187
|
+
const reqBody = (await request.json()) as Record<string, unknown>;
|
|
188
|
+
reqBody.walletType = WalletKind.unknown;
|
|
189
|
+
|
|
190
|
+
// For non-Sequence wallet - return tokenApproval and createOffer steps
|
|
191
|
+
return HttpResponse.json({
|
|
192
|
+
steps: createMockSteps([
|
|
193
|
+
StepType.tokenApproval,
|
|
194
|
+
StepType.createOffer,
|
|
195
|
+
]),
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
),
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
const { result } = renderHook(() =>
|
|
202
|
+
useGenerateOfferTransaction(defaultArgs),
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
await result.current.generateOfferTransactionAsync(mockTransactionProps);
|
|
206
|
+
|
|
207
|
+
expect(mockOnSuccess).toHaveBeenCalled();
|
|
208
|
+
const steps = mockOnSuccess.mock.calls[0]?.[0];
|
|
209
|
+
|
|
210
|
+
// Verify there are two steps: tokenApproval and createOffer
|
|
211
|
+
expect(steps).toHaveLength(2);
|
|
212
|
+
expect(steps[0].id).toBe('tokenApproval');
|
|
213
|
+
expect(steps[1].id).toBe('createOffer');
|
|
214
|
+
|
|
215
|
+
// Restore the original useWallet implementation
|
|
216
|
+
useWalletSpy.mockRestore();
|
|
217
|
+
});
|
|
218
|
+
});
|
|
161
219
|
});
|
|
@@ -3,13 +3,14 @@ import { http, HttpResponse } from 'msw';
|
|
|
3
3
|
import { zeroAddress } from 'viem';
|
|
4
4
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
5
|
import {
|
|
6
|
+
createMockSteps,
|
|
6
7
|
mockMarketplaceEndpoint,
|
|
7
|
-
mockSteps,
|
|
8
8
|
} from '../../_internal/api/__mocks__/marketplace.msw';
|
|
9
9
|
import {
|
|
10
10
|
ContractType,
|
|
11
11
|
MarketplaceKind,
|
|
12
12
|
OrderbookKind,
|
|
13
|
+
StepType,
|
|
13
14
|
} from '../../_internal/api/marketplace.gen';
|
|
14
15
|
import { useGenerateSellTransaction } from '../useGenerateSellTransaction';
|
|
15
16
|
|
|
@@ -52,12 +53,18 @@ describe('useGenerateSellTransaction', () => {
|
|
|
52
53
|
[
|
|
53
54
|
{
|
|
54
55
|
"data": "0x...",
|
|
55
|
-
"executeType": "order",
|
|
56
56
|
"id": "tokenApproval",
|
|
57
57
|
"price": "0",
|
|
58
58
|
"to": "0x1234567890123456789012345678901234567890",
|
|
59
59
|
"value": "0",
|
|
60
60
|
},
|
|
61
|
+
{
|
|
62
|
+
"data": "0x...",
|
|
63
|
+
"id": "sell",
|
|
64
|
+
"price": "0",
|
|
65
|
+
"to": "0x1234567890123456789012345678901234567890",
|
|
66
|
+
"value": "0",
|
|
67
|
+
},
|
|
61
68
|
],
|
|
62
69
|
{
|
|
63
70
|
"additionalFees": [],
|
|
@@ -87,7 +94,7 @@ describe('useGenerateSellTransaction', () => {
|
|
|
87
94
|
|
|
88
95
|
await waitFor(() => {
|
|
89
96
|
expect(mockOnSuccess).toHaveBeenCalledWith(
|
|
90
|
-
|
|
97
|
+
createMockSteps([StepType.tokenApproval, StepType.sell]),
|
|
91
98
|
mockTransactionProps,
|
|
92
99
|
undefined,
|
|
93
100
|
);
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { renderHook, server, waitFor } from '@test';
|
|
2
|
+
import { http, HttpResponse } from 'msw';
|
|
3
|
+
import { zeroAddress } from 'viem';
|
|
4
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import {
|
|
6
|
+
mockIndexerEndpoint,
|
|
7
|
+
mockTokenBalance,
|
|
8
|
+
} from '../../_internal/api/__mocks__/indexer.msw';
|
|
9
|
+
import {
|
|
10
|
+
mockCollectibleOrder,
|
|
11
|
+
mockMarketplaceEndpoint,
|
|
12
|
+
} from '../../_internal/api/__mocks__/marketplace.msw';
|
|
13
|
+
import type { UseInventoryArgs } from '../../queries/inventory';
|
|
14
|
+
import { mockConfig } from '../options/__mocks__/marketplaceConfig.msw';
|
|
15
|
+
import { useInventory } from '../useInventory';
|
|
16
|
+
|
|
17
|
+
// Make sure mockCollectibleOrder has a tokenId of "1" for tests
|
|
18
|
+
mockCollectibleOrder.metadata.tokenId = '1';
|
|
19
|
+
|
|
20
|
+
describe('useInventory', () => {
|
|
21
|
+
const defaultArgs: UseInventoryArgs = {
|
|
22
|
+
accountAddress:
|
|
23
|
+
'0x1234567890123456789012345678901234567890' as `0x${string}`,
|
|
24
|
+
chainId: 1,
|
|
25
|
+
collectionAddress: zeroAddress,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
// Reset MSW handlers before each test to ensure a clean state
|
|
30
|
+
server.resetHandlers();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should fetch inventory data successfully', async () => {
|
|
34
|
+
const { result } = renderHook(() => useInventory(defaultArgs));
|
|
35
|
+
|
|
36
|
+
// Initially loading
|
|
37
|
+
expect(result.current.isLoading).toBe(true);
|
|
38
|
+
expect(result.current.data).toBeUndefined();
|
|
39
|
+
|
|
40
|
+
// Wait for data to be loaded
|
|
41
|
+
await waitFor(() => {
|
|
42
|
+
expect(result.current.isLoading).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Verify the data is defined and has pages
|
|
46
|
+
expect(result.current.data).toBeDefined();
|
|
47
|
+
expect(result.current.data?.pages).toBeDefined();
|
|
48
|
+
expect(result.current.error).toBeNull();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should handle error gracefully', async () => {
|
|
52
|
+
// Mock both API endpoints to return errors
|
|
53
|
+
server.use(
|
|
54
|
+
http.post(mockMarketplaceEndpoint('ListCollectibles'), () => {
|
|
55
|
+
return new HttpResponse(null, { status: 500 });
|
|
56
|
+
}),
|
|
57
|
+
http.post(mockIndexerEndpoint('GetTokenBalances'), () => {
|
|
58
|
+
return new HttpResponse(null, { status: 500 });
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const { result } = renderHook(() =>
|
|
63
|
+
useInventory({
|
|
64
|
+
...defaultArgs,
|
|
65
|
+
// Add a unique key to avoid caching
|
|
66
|
+
collectionAddress:
|
|
67
|
+
'0xdeadbeef0000000000000000000000000000dead' as `0x${string}`,
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Wait for the query to finish loading and show error
|
|
72
|
+
await waitFor(
|
|
73
|
+
() => {
|
|
74
|
+
expect(result.current.isLoading).toBe(false);
|
|
75
|
+
},
|
|
76
|
+
{ timeout: 3000 },
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Verify error state
|
|
80
|
+
expect(result.current.status).toBe('error');
|
|
81
|
+
expect(result.current.isError).toBe(true);
|
|
82
|
+
expect(result.current.error).not.toBeNull();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should refetch when args change', async () => {
|
|
86
|
+
const { result, rerender } = renderHook(() => useInventory(defaultArgs));
|
|
87
|
+
|
|
88
|
+
// Wait for initial data
|
|
89
|
+
await waitFor(() => {
|
|
90
|
+
expect(result.current.isLoading).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Change args and rerender with a new hook
|
|
94
|
+
const newArgs = {
|
|
95
|
+
...defaultArgs,
|
|
96
|
+
collectionAddress:
|
|
97
|
+
'0x1234567890123456789012345678901234567890' as `0x${string}`,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
rerender(() => useInventory(newArgs));
|
|
101
|
+
|
|
102
|
+
// Wait for new data
|
|
103
|
+
await waitFor(() => {
|
|
104
|
+
expect(result.current.data).toBeDefined();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Verify that the query was refetched with new args
|
|
108
|
+
expect(result.current.data).toBeDefined();
|
|
109
|
+
expect(result.current.isSuccess).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should handle disabled queries', async () => {
|
|
113
|
+
const disabledArgs: UseInventoryArgs = {
|
|
114
|
+
...defaultArgs,
|
|
115
|
+
query: {
|
|
116
|
+
enabled: false,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const { result } = renderHook(() => useInventory(disabledArgs));
|
|
121
|
+
|
|
122
|
+
// Should not be loading or have data
|
|
123
|
+
expect(result.current.isLoading).toBe(false);
|
|
124
|
+
expect(result.current.data).toBeUndefined();
|
|
125
|
+
expect(result.current.isFetched).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should use isLaos721 flag from marketplaceConfig', async () => {
|
|
129
|
+
// Setup config with LAOS collection
|
|
130
|
+
const laosCollectionAddress = '0x1234567890123456789012345678901234567890';
|
|
131
|
+
server.use(
|
|
132
|
+
http.get('*/marketplace/*/settings.json', () => {
|
|
133
|
+
const configWithLaos = {
|
|
134
|
+
...mockConfig,
|
|
135
|
+
collections: [
|
|
136
|
+
{
|
|
137
|
+
...mockConfig.collections[0],
|
|
138
|
+
address: laosCollectionAddress,
|
|
139
|
+
isLAOSERC721: true,
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
};
|
|
143
|
+
return HttpResponse.json(configWithLaos);
|
|
144
|
+
}),
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const laosArgs: UseInventoryArgs = {
|
|
148
|
+
...defaultArgs,
|
|
149
|
+
collectionAddress: laosCollectionAddress as `0x${string}`,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const { result } = renderHook(() => useInventory(laosArgs));
|
|
153
|
+
|
|
154
|
+
await waitFor(() => {
|
|
155
|
+
expect(result.current.isLoading).toBe(false);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
expect(result.current.data).toBeDefined();
|
|
159
|
+
expect(result.current.isSuccess).toBe(true);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should fetch data from indexer when marketplace API has no more results', async () => {
|
|
163
|
+
// Mock marketplace API with empty results
|
|
164
|
+
server.use(
|
|
165
|
+
http.post(mockMarketplaceEndpoint('ListCollectibles'), () => {
|
|
166
|
+
return HttpResponse.json({
|
|
167
|
+
collectibles: [],
|
|
168
|
+
page: {
|
|
169
|
+
page: 1,
|
|
170
|
+
pageSize: 50,
|
|
171
|
+
more: false,
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
}),
|
|
175
|
+
// Mock indexer with data
|
|
176
|
+
http.post(mockIndexerEndpoint('GetTokenBalances'), () => {
|
|
177
|
+
return HttpResponse.json({
|
|
178
|
+
balances: [mockTokenBalance],
|
|
179
|
+
page: {
|
|
180
|
+
page: 1,
|
|
181
|
+
pageSize: 50,
|
|
182
|
+
more: false,
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
}),
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const { result } = renderHook(() => useInventory(defaultArgs));
|
|
189
|
+
|
|
190
|
+
await waitFor(() => {
|
|
191
|
+
expect(result.current.isLoading).toBe(false);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
expect(result.current.data).toBeDefined();
|
|
195
|
+
expect(result.current.data?.pages[0].collectibles).toBeDefined();
|
|
196
|
+
expect(result.current.isSuccess).toBe(true);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should support pagination with fetchNextPage', async () => {
|
|
200
|
+
// Simplified test for pagination
|
|
201
|
+
// Set up mock data for first and second pages
|
|
202
|
+
const page1Data = {
|
|
203
|
+
collectibles: [
|
|
204
|
+
{
|
|
205
|
+
...mockCollectibleOrder,
|
|
206
|
+
metadata: {
|
|
207
|
+
...mockCollectibleOrder.metadata,
|
|
208
|
+
tokenId: '1',
|
|
209
|
+
name: 'Token 1',
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
page: {
|
|
214
|
+
page: 1,
|
|
215
|
+
pageSize: 10,
|
|
216
|
+
more: true, // indicate there's a next page
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// Mock API to return data for the first page
|
|
221
|
+
server.use(
|
|
222
|
+
http.post(
|
|
223
|
+
mockMarketplaceEndpoint('ListCollectibles'),
|
|
224
|
+
async ({ request }) => {
|
|
225
|
+
const body = (await request.json()) as { page?: number };
|
|
226
|
+
const pageNumber = body?.page || 1;
|
|
227
|
+
|
|
228
|
+
// Return first page data
|
|
229
|
+
if (pageNumber === 1) {
|
|
230
|
+
return HttpResponse.json(page1Data);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// For second page, return empty collectibles but with more=false
|
|
234
|
+
return HttpResponse.json({
|
|
235
|
+
collectibles: [],
|
|
236
|
+
page: {
|
|
237
|
+
page: 2,
|
|
238
|
+
pageSize: 10,
|
|
239
|
+
more: false,
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
),
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
// Use unique test args to avoid caching issues
|
|
247
|
+
const testArgs = {
|
|
248
|
+
...defaultArgs,
|
|
249
|
+
accountAddress:
|
|
250
|
+
'0xabcdef1234567890abcdef1234567890abcdef12' as `0x${string}`,
|
|
251
|
+
collectionAddress:
|
|
252
|
+
'0xabcdef1234567890abcdef1234567890abcdef12' as `0x${string}`,
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const { result } = renderHook(() => useInventory(testArgs));
|
|
256
|
+
|
|
257
|
+
// Wait for the first page to load
|
|
258
|
+
await waitFor(
|
|
259
|
+
() => {
|
|
260
|
+
expect(result.current.isLoading).toBe(false);
|
|
261
|
+
expect(result.current.data?.pages).toBeDefined();
|
|
262
|
+
},
|
|
263
|
+
{ timeout: 5000 },
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
// Verify first page data loaded correctly
|
|
267
|
+
expect(result.current.data?.pages[0].collectibles).toBeDefined();
|
|
268
|
+
expect(result.current.data?.pages[0].collectibles.length).toBeGreaterThan(
|
|
269
|
+
0,
|
|
270
|
+
);
|
|
271
|
+
// Check that at least one item has the expected tokenId
|
|
272
|
+
expect(
|
|
273
|
+
result.current.data?.pages[0].collectibles.some(
|
|
274
|
+
(c) => c.metadata.tokenId === '1',
|
|
275
|
+
),
|
|
276
|
+
).toBe(true);
|
|
277
|
+
expect(result.current.hasNextPage).toBe(true);
|
|
278
|
+
|
|
279
|
+
// Fetch the next page
|
|
280
|
+
await result.current.fetchNextPage();
|
|
281
|
+
|
|
282
|
+
// Wait for second page to load
|
|
283
|
+
await waitFor(
|
|
284
|
+
() => {
|
|
285
|
+
expect(result.current.data?.pages.length).toBe(2);
|
|
286
|
+
},
|
|
287
|
+
{ timeout: 5000 },
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
// For an empty second page we just verify it exists
|
|
291
|
+
expect(result.current.data?.pages[1]).toBeDefined();
|
|
292
|
+
expect(result.current.hasNextPage).toBe(false); // No more pages
|
|
293
|
+
});
|
|
294
|
+
});
|
package/src/react/hooks/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './useCurrency';
|
|
|
12
12
|
export * from './useFilters';
|
|
13
13
|
export * from './useFloorOrder';
|
|
14
14
|
export * from './useHighestOffer';
|
|
15
|
+
export * from './useInventory';
|
|
15
16
|
export * from './useListBalances';
|
|
16
17
|
export * from './useListCollectibleActivities';
|
|
17
18
|
export * from './useListCollectibles';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Address, zeroAddress } from 'viem';
|
|
2
2
|
|
|
3
3
|
import { useChain } from '@0xsequence/connect';
|
|
4
|
-
import { useCallback } from 'react';
|
|
4
|
+
import { useCallback, useEffect } from 'react';
|
|
5
5
|
import { useAccount } from 'wagmi';
|
|
6
6
|
import type { FeeOption } from '../../types/waas-types';
|
|
7
7
|
import { useCollectionBalanceDetails } from './useCollectionBalanceDetails';
|
|
@@ -19,6 +19,7 @@ type UseAutoSelectFeeOptionArgs = {
|
|
|
19
19
|
options: FeeOption[] | undefined;
|
|
20
20
|
chainId: number;
|
|
21
21
|
};
|
|
22
|
+
enabled?: boolean;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -87,6 +88,7 @@ type UseAutoSelectFeeOptionArgs = {
|
|
|
87
88
|
*/
|
|
88
89
|
export function useAutoSelectFeeOption({
|
|
89
90
|
pendingFeeOptionConfirmation,
|
|
91
|
+
enabled,
|
|
90
92
|
}: UseAutoSelectFeeOptionArgs) {
|
|
91
93
|
const { address: userAddress } = useAccount();
|
|
92
94
|
|
|
@@ -110,7 +112,8 @@ export function useAutoSelectFeeOption({
|
|
|
110
112
|
omitNativeBalances: false,
|
|
111
113
|
},
|
|
112
114
|
query: {
|
|
113
|
-
enabled:
|
|
115
|
+
enabled:
|
|
116
|
+
!!pendingFeeOptionConfirmation.options && !!userAddress && enabled,
|
|
114
117
|
},
|
|
115
118
|
});
|
|
116
119
|
const chain = useChain(pendingFeeOptionConfirmation.chainId);
|
|
@@ -131,7 +134,11 @@ export function useAutoSelectFeeOption({
|
|
|
131
134
|
})),
|
|
132
135
|
];
|
|
133
136
|
|
|
134
|
-
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (combinedBalances) {
|
|
139
|
+
console.debug('currency balances', combinedBalances);
|
|
140
|
+
}
|
|
141
|
+
}, [combinedBalances]);
|
|
135
142
|
|
|
136
143
|
const autoSelectedOption = useCallback(async () => {
|
|
137
144
|
if (!userAddress) {
|