@0xsequence/marketplace-sdk 0.4.6 → 0.4.8

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 (274) hide show
  1. package/dist/alien_swap-4GAIV7PA.png +0 -0
  2. package/dist/alien_swap-IZONL4XB.js +8 -0
  3. package/dist/alien_swap-PMYKGY6A.js +8 -0
  4. package/dist/aqua-xyz-HLNZIFE2.js +8 -0
  5. package/dist/aqua-xyz-HLNZIFE2.js.map +1 -0
  6. package/dist/aqua-xyz-JY5QCI5L.js +8 -0
  7. package/dist/aqua-xyz-JY5QCI5L.js.map +1 -0
  8. package/dist/aqua-xyz-WU4JVU2K.png +0 -0
  9. package/dist/aura-CYKEACX2.js +8 -0
  10. package/dist/aura-CYKEACX2.js.map +1 -0
  11. package/dist/aura-HLMWKNSP.js +8 -0
  12. package/dist/aura-HLMWKNSP.js.map +1 -0
  13. package/dist/aura-RITZV42R.png +0 -0
  14. package/dist/blur-2ABQMPTL.png +0 -0
  15. package/dist/blur-MIPRQYJL.js +8 -0
  16. package/dist/blur-MIPRQYJL.js.map +1 -0
  17. package/dist/blur-XDIGHYB7.js +8 -0
  18. package/dist/blur-XDIGHYB7.js.map +1 -0
  19. package/dist/{chunk-QVOUL555.js → chunk-6R4G7J6Q.js} +86 -26
  20. package/dist/chunk-6R4G7J6Q.js.map +1 -0
  21. package/dist/{chunk-2FOUCP2R.js → chunk-7WCZP6FN.js} +743 -744
  22. package/dist/chunk-7WCZP6FN.js.map +1 -0
  23. package/dist/{chunk-RD7HPANB.js → chunk-AQT3BQ67.js} +9 -9
  24. package/dist/chunk-AQT3BQ67.js.map +1 -0
  25. package/dist/{chunk-ZEH4JI2U.js → chunk-FCF57DZI.js} +7 -2
  26. package/dist/chunk-FCF57DZI.js.map +1 -0
  27. package/dist/{chunk-3C2MT5TM.js → chunk-FWN2MCLI.js} +12 -6
  28. package/dist/chunk-FWN2MCLI.js.map +1 -0
  29. package/dist/{chunk-5D3ARFFZ.js → chunk-JEOUQFT3.js} +17 -129
  30. package/dist/chunk-JEOUQFT3.js.map +1 -0
  31. package/dist/chunk-MWDG7UTB.js +132 -0
  32. package/dist/chunk-MWDG7UTB.js.map +1 -0
  33. package/dist/chunk-RK6KYMZM.js +18 -0
  34. package/dist/chunk-RK6KYMZM.js.map +1 -0
  35. package/dist/{chunk-36NGHJH5.js → chunk-WRMJ5FZM.js} +140 -37
  36. package/dist/chunk-WRMJ5FZM.js.map +1 -0
  37. package/dist/{chunk-LTHX6RXH.js → chunk-XP3WY5AX.js} +90 -2
  38. package/dist/chunk-XP3WY5AX.js.map +1 -0
  39. package/dist/{chunk-DNVERQ5J.js → chunk-YOKGP2EQ.js} +1 -1
  40. package/dist/chunk-YOKGP2EQ.js.map +1 -0
  41. package/dist/chunk-ZUEQGPLO.js +302 -0
  42. package/dist/chunk-ZUEQGPLO.js.map +1 -0
  43. package/dist/coinbase-MIJPE653.js +8 -0
  44. package/dist/coinbase-MIJPE653.js.map +1 -0
  45. package/dist/coinbase-MZUBBEC4.png +0 -0
  46. package/dist/coinbase-T24XHLQL.js +8 -0
  47. package/dist/coinbase-T24XHLQL.js.map +1 -0
  48. package/dist/{create-config-BBTTSJyp.d.ts → create-config-D5WqfUft.d.ts} +2 -2
  49. package/dist/element-GHIPFSB6.png +0 -0
  50. package/dist/element-MWATR3ON.js +8 -0
  51. package/dist/element-MWATR3ON.js.map +1 -0
  52. package/dist/element-X45NH4D7.js +8 -0
  53. package/dist/element-X45NH4D7.js.map +1 -0
  54. package/dist/foundation-BDJUT6CK.js +8 -0
  55. package/dist/foundation-BDJUT6CK.js.map +1 -0
  56. package/dist/foundation-FJKIXLS5.png +0 -0
  57. package/dist/foundation-Z6D6U74V.js +8 -0
  58. package/dist/foundation-Z6D6U74V.js.map +1 -0
  59. package/dist/index.d.ts +6 -4
  60. package/dist/index.js +11 -5
  61. package/dist/looks-rare-B6G3OQAP.png +0 -0
  62. package/dist/looks-rare-LBHT6EXZ.js +8 -0
  63. package/dist/looks-rare-LBHT6EXZ.js.map +1 -0
  64. package/dist/looks-rare-STS6IKI4.js +8 -0
  65. package/dist/looks-rare-STS6IKI4.js.map +1 -0
  66. package/dist/magic-eden-HA3X3P2O.png +0 -0
  67. package/dist/magic-eden-RMZ24554.js +8 -0
  68. package/dist/magic-eden-RMZ24554.js.map +1 -0
  69. package/dist/magic-eden-YMTLPKLE.js +8 -0
  70. package/dist/magic-eden-YMTLPKLE.js.map +1 -0
  71. package/dist/manifold-I4NT4V5L.png +0 -0
  72. package/dist/manifold-L7FLFDRO.js +8 -0
  73. package/dist/manifold-L7FLFDRO.js.map +1 -0
  74. package/dist/manifold-YIUSABCZ.js +8 -0
  75. package/dist/manifold-YIUSABCZ.js.map +1 -0
  76. package/dist/{marketplace-config-vioKvBQe.d.ts → marketplace-config-C_fDWzz0.d.ts} +2 -2
  77. package/dist/marketplace.gen-B8S8fflj.d.ts +390 -0
  78. package/dist/mintify-ARDASD5Z.js +8 -0
  79. package/dist/mintify-ARDASD5Z.js.map +1 -0
  80. package/dist/mintify-OLOGFTWQ.png +0 -0
  81. package/dist/mintify-TSZA3SQT.js +8 -0
  82. package/dist/mintify-TSZA3SQT.js.map +1 -0
  83. package/dist/nftx-67RX7ZV6.js +8 -0
  84. package/dist/nftx-67RX7ZV6.js.map +1 -0
  85. package/dist/nftx-DJIV3PYG.png +0 -0
  86. package/dist/nftx-KVJ3T3G2.js +8 -0
  87. package/dist/nftx-KVJ3T3G2.js.map +1 -0
  88. package/dist/okx-MOA2EFVR.js +8 -0
  89. package/dist/okx-MOA2EFVR.js.map +1 -0
  90. package/dist/okx-WNQRV3WE.png +0 -0
  91. package/dist/okx-WQA7H7EM.js +8 -0
  92. package/dist/okx-WQA7H7EM.js.map +1 -0
  93. package/dist/open-sea-2HWFM4P6.js +8 -0
  94. package/dist/open-sea-2HWFM4P6.js.map +1 -0
  95. package/dist/open-sea-C57XWTAR.png +0 -0
  96. package/dist/open-sea-GESD6S2M.js +8 -0
  97. package/dist/open-sea-GESD6S2M.js.map +1 -0
  98. package/dist/rarible-GHMFCPBT.js +8 -0
  99. package/dist/rarible-GHMFCPBT.js.map +1 -0
  100. package/dist/rarible-QNNAZZQC.js +8 -0
  101. package/dist/rarible-QNNAZZQC.js.map +1 -0
  102. package/dist/rarible-ZCE7U3I5.png +0 -0
  103. package/dist/react/_internal/api/index.d.ts +4 -2
  104. package/dist/react/_internal/api/index.js +5 -1
  105. package/dist/react/_internal/index.d.ts +5 -5
  106. package/dist/react/_internal/index.js +7 -3
  107. package/dist/react/_internal/wagmi/index.d.ts +3 -3
  108. package/dist/react/_internal/wagmi/index.js +1 -1
  109. package/dist/react/hooks/index.d.ts +668 -5
  110. package/dist/react/hooks/index.js +16 -6
  111. package/dist/react/index.d.ts +7 -7
  112. package/dist/react/index.js +18 -9
  113. package/dist/react/ssr/index.js +14 -31
  114. package/dist/react/ssr/index.js.map +1 -1
  115. package/dist/react/ui/components/collectible-card/index.css.map +1 -0
  116. package/dist/react/ui/components/{index.d.ts → collectible-card/index.d.ts} +3 -3
  117. package/dist/react/ui/components/collectible-card/index.js +29 -0
  118. package/dist/react/ui/components/collectible-card/index.js.map +1 -0
  119. package/dist/react/ui/components/marketplace-logos/index.d.ts +26 -0
  120. package/dist/react/ui/components/marketplace-logos/index.js +46 -0
  121. package/dist/react/ui/components/marketplace-logos/index.js.map +1 -0
  122. package/dist/react/ui/icons/index.js +0 -8
  123. package/dist/react/ui/icons/index.js.map +1 -1
  124. package/dist/react/ui/index.d.ts +4 -4
  125. package/dist/react/ui/index.js +10 -9
  126. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +4 -3
  127. package/dist/react/ui/modals/_internal/components/actionModal/index.js +8 -6
  128. package/dist/{sdk-config-CasNGLz4.d.ts → sdk-config-BXVH8PS2.d.ts} +68 -16
  129. package/dist/sequence-JAFBEQNI.png +0 -0
  130. package/dist/sequence-OIPVNE5P.js +8 -0
  131. package/dist/sequence-OIPVNE5P.js.map +1 -0
  132. package/dist/sequence-QNNBU34G.js +8 -0
  133. package/dist/sequence-QNNBU34G.js.map +1 -0
  134. package/dist/{services-CbsurKYr.d.ts → services-CdXAIjt1.d.ts} +1 -1
  135. package/dist/sudo-swap-D3FAP7W4.js +8 -0
  136. package/dist/sudo-swap-D3FAP7W4.js.map +1 -0
  137. package/dist/sudo-swap-XNJ3BIUD.js +8 -0
  138. package/dist/sudo-swap-XNJ3BIUD.js.map +1 -0
  139. package/dist/sudo-swap-Y6GICQTL.png +0 -0
  140. package/dist/super-rare-VIUS3P6B.js +8 -0
  141. package/dist/super-rare-VIUS3P6B.js.map +1 -0
  142. package/dist/super-rare-WWXZ3MQL.png +0 -0
  143. package/dist/super-rare-YPU3Y7EF.js +8 -0
  144. package/dist/super-rare-YPU3Y7EF.js.map +1 -0
  145. package/dist/types/index.d.ts +3 -3
  146. package/dist/types/index.js +8 -5
  147. package/dist/{types-rupsBCjv.d.ts → types-eX4P9xju.d.ts} +2 -2
  148. package/dist/utils/index.d.ts +16 -4
  149. package/dist/utils/index.js +8 -1
  150. package/dist/x2y2-CXOXXZKS.png +0 -0
  151. package/dist/x2y2-G2SXS5VR.js +8 -0
  152. package/dist/x2y2-G2SXS5VR.js.map +1 -0
  153. package/dist/x2y2-GKWTQTPB.js +8 -0
  154. package/dist/x2y2-GKWTQTPB.js.map +1 -0
  155. package/dist/zora-3DPG4KAY.png +0 -0
  156. package/dist/zora-JUDT67NX.js +8 -0
  157. package/dist/zora-JUDT67NX.js.map +1 -0
  158. package/dist/zora-Z5VR477F.js +8 -0
  159. package/dist/zora-Z5VR477F.js.map +1 -0
  160. package/package.json +34 -19
  161. package/src/react/__tests__/provider.test.tsx +75 -0
  162. package/src/react/_internal/api/__mocks__/marketplace.msw.ts +218 -0
  163. package/src/react/_internal/api/marketplace.gen.ts +125 -42
  164. package/src/react/_internal/api/query-keys.ts +8 -0
  165. package/src/react/_internal/api/zod-schema.ts +33 -0
  166. package/src/react/_internal/test-utils.tsx +68 -0
  167. package/src/react/_internal/types.ts +3 -3
  168. package/src/react/_internal/wagmi/__tests__/create-config.test.ts +196 -0
  169. package/src/react/_internal/wagmi/create-config.ts +9 -1
  170. package/src/react/hooks/index.ts +2 -0
  171. package/src/react/hooks/options/__mocks__/marketplaceConfig.msw.ts +77 -0
  172. package/src/react/hooks/options/__tests__/marketplaceConfigOptions.test.tsx +144 -0
  173. package/src/react/hooks/useCancelOrder.tsx +1 -1
  174. package/src/react/hooks/useCancelTransactionSteps.tsx +6 -6
  175. package/src/react/hooks/useCurrencies.tsx +2 -5
  176. package/src/react/hooks/useCurrency.tsx +10 -1
  177. package/src/react/hooks/useCurrencyBalance.tsx +38 -36
  178. package/src/react/hooks/useGetReceiptFromHash.tsx +1 -1
  179. package/src/react/hooks/useListCollectibleActivities.tsx +57 -0
  180. package/src/react/hooks/useListCollectionActivities.tsx +57 -0
  181. package/src/react/provider.tsx +5 -0
  182. package/src/react/ssr/create-ssr-client.ts +1 -1
  183. package/src/react/ui/components/_internals/custom-select/__tests__/CustomSelect.test.tsx +89 -0
  184. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +9 -8
  185. package/src/react/ui/components/collectible-card/Footer.tsx +4 -1
  186. package/src/react/ui/components/collectible-card/index.ts +1 -0
  187. package/src/react/ui/components/marketplace-logos/index.ts +23 -0
  188. package/src/react/ui/components/marketplace-logos/marketplace-logos.tsx +111 -0
  189. package/src/react/ui/images/marketplaces/alien_swap.png +0 -0
  190. package/src/react/ui/images/marketplaces/aqua-xyz.png +0 -0
  191. package/src/react/ui/images/marketplaces/aura.png +0 -0
  192. package/src/react/ui/images/marketplaces/blur.png +0 -0
  193. package/src/react/ui/images/marketplaces/coinbase.png +0 -0
  194. package/src/react/ui/images/marketplaces/element.png +0 -0
  195. package/src/react/ui/images/marketplaces/foundation.png +0 -0
  196. package/src/react/ui/images/marketplaces/looks-rare.png +0 -0
  197. package/src/react/ui/images/marketplaces/magic-eden.png +0 -0
  198. package/src/react/ui/images/marketplaces/manifold.png +0 -0
  199. package/src/react/ui/images/marketplaces/mintify.png +0 -0
  200. package/src/react/ui/images/marketplaces/nftx.png +0 -0
  201. package/src/react/ui/images/marketplaces/okx.png +0 -0
  202. package/src/react/ui/images/marketplaces/open-sea.png +0 -0
  203. package/src/react/ui/images/marketplaces/rarible.png +0 -0
  204. package/src/react/ui/images/marketplaces/sequence.png +0 -0
  205. package/src/react/ui/images/marketplaces/sudo-swap.png +0 -0
  206. package/src/react/ui/images/marketplaces/super-rare.png +0 -0
  207. package/src/react/ui/images/marketplaces/x2y2.png +0 -0
  208. package/src/react/ui/images/marketplaces/zora.png +0 -0
  209. package/src/react/ui/modals/BuyModal/Modal.tsx +14 -3
  210. package/src/react/ui/modals/BuyModal/hooks/useBuyCollectable.ts +1 -0
  211. package/src/react/ui/modals/BuyModal/modals/CheckoutModal.tsx +7 -0
  212. package/src/react/ui/modals/CreateListingModal/Modal.tsx +2 -1
  213. package/src/react/ui/modals/CreateListingModal/__tests__/Modal.test.tsx +208 -0
  214. package/src/react/ui/modals/CreateListingModal/store.ts +26 -16
  215. package/src/react/ui/modals/MakeOfferModal/Modal.tsx +2 -2
  216. package/src/react/ui/modals/MakeOfferModal/__tests__/Modal.test.tsx +199 -0
  217. package/src/react/ui/modals/MakeOfferModal/store.ts +27 -16
  218. package/src/react/ui/modals/SellModal/Modal.tsx +1 -0
  219. package/src/react/ui/modals/SellModal/__tests__/Modal.test.tsx +192 -0
  220. package/src/react/ui/modals/SellModal/hooks/useGetTokenApproval.tsx +3 -3
  221. package/src/react/ui/modals/SellModal/hooks/useSell.tsx +3 -3
  222. package/src/react/ui/modals/SellModal/hooks/useTransactionSteps.tsx +8 -8
  223. package/src/react/ui/modals/SuccessfulPurchaseModal/__tests__/Modal.test.tsx +145 -0
  224. package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +2 -0
  225. package/src/react/ui/modals/_internal/components/actionModal/ErrorModal.tsx +7 -1
  226. package/src/react/ui/modals/_internal/components/actionModal/LoadingModal.tsx +7 -1
  227. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +159 -0
  228. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +4 -5
  229. package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +124 -0
  230. package/src/react/ui/modals/_internal/components/priceInput/index.tsx +48 -45
  231. package/src/react/ui/modals/_internal/components/switchChainModal/__tests__/SwitchChainModal.test.tsx +221 -0
  232. package/src/react/ui/modals/_internal/components/switchChainModal/index.tsx +24 -5
  233. package/src/react/ui/modals/_internal/components/switchChainModal/store.ts +2 -2
  234. package/src/react/ui/modals/_internal/components/transactionPreview/index.tsx +16 -2
  235. package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/TransactionStatusModal.test.tsx +147 -0
  236. package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/utils.test.ts +218 -0
  237. package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +27 -10
  238. package/src/react/ui/modals/_internal/components/transactionStatusModal/util/getMessage.ts +1 -1
  239. package/src/react/ui/modals/modal-provider.tsx +0 -2
  240. package/src/types/marketplace-config.ts +1 -1
  241. package/src/utils/__tests__/address.test.ts +65 -0
  242. package/src/utils/__tests__/date.test.ts +31 -0
  243. package/src/utils/__tests__/get-public-rpc-client.test.ts +109 -0
  244. package/src/utils/__tests__/getMarketplaceDetails.test.ts +134 -0
  245. package/src/utils/__tests__/price.test.ts +42 -0
  246. package/src/utils/_internal/error/config.ts +16 -0
  247. package/src/utils/get-public-rpc-client.ts +6 -0
  248. package/src/utils/getMarketplaceDetails.ts +110 -0
  249. package/src/utils/index.ts +1 -0
  250. package/tsconfig.tsbuildinfo +1 -1
  251. package/vitest.config.js +10 -0
  252. package/dist/chunk-2FOUCP2R.js.map +0 -1
  253. package/dist/chunk-36NGHJH5.js.map +0 -1
  254. package/dist/chunk-3C2MT5TM.js.map +0 -1
  255. package/dist/chunk-5D3ARFFZ.js.map +0 -1
  256. package/dist/chunk-6WB4GCCJ.js +0 -38
  257. package/dist/chunk-6WB4GCCJ.js.map +0 -1
  258. package/dist/chunk-CP2IVRMX.js +0 -85
  259. package/dist/chunk-CP2IVRMX.js.map +0 -1
  260. package/dist/chunk-DNVERQ5J.js.map +0 -1
  261. package/dist/chunk-LTHX6RXH.js.map +0 -1
  262. package/dist/chunk-MJ4YU7RW.js +0 -2
  263. package/dist/chunk-QVOUL555.js.map +0 -1
  264. package/dist/chunk-RD7HPANB.js.map +0 -1
  265. package/dist/chunk-ZEH4JI2U.js.map +0 -1
  266. package/dist/react/ui/components/index.css.map +0 -1
  267. package/dist/react/ui/components/index.js +0 -28
  268. package/src/react/ui/components/index.ts +0 -1
  269. package/src/react/ui/modals/Account/index.tsx +0 -29
  270. package/src/react/ui/modals/_internal/components/priceInput/hooks/useBalanceCheck.ts +0 -67
  271. package/src/react/ui/modals/_internal/components/priceInput/hooks/usePriceInput.ts +0 -54
  272. /package/dist/{chunk-MJ4YU7RW.js.map → alien_swap-IZONL4XB.js.map} +0 -0
  273. /package/dist/{react/ui/components/index.js.map → alien_swap-PMYKGY6A.js.map} +0 -0
  274. /package/dist/react/ui/components/{index.css → collectible-card/index.css} +0 -0
@@ -0,0 +1,147 @@
1
+ import {
2
+ render,
3
+ cleanup,
4
+ screen,
5
+ waitFor,
6
+ } from '../../../../../../_internal/test-utils';
7
+ import '@testing-library/jest-dom/vitest';
8
+ import TransactionStatusModal from '../index';
9
+ import { transactionStatusModal$ } from '../store';
10
+ import type { ShowTransactionStatusModalArgs } from '../index';
11
+ import { TransactionType } from '../../../../../../_internal/types';
12
+ import { beforeEach, describe, expect, it, vi, afterEach } from 'vitest';
13
+ import { WaitForTransactionReceiptTimeoutError } from 'viem';
14
+
15
+ const mockTransactionArgs: ShowTransactionStatusModalArgs = {
16
+ hash: '0x123' as `0x${string}`,
17
+ collectionAddress: '0x456' as `0x${string}`,
18
+ chainId: '1',
19
+ collectibleId: '1',
20
+ type: TransactionType.BUY,
21
+ };
22
+
23
+ const mockPublicClient = {
24
+ waitForTransactionReceipt: vi.fn(),
25
+ };
26
+
27
+ vi.mock('../../../../../../../utils/get-public-rpc-client', () => ({
28
+ getPublicRpcClient: vi.fn().mockImplementation(() => mockPublicClient),
29
+ }));
30
+
31
+ describe('TransactionStatusModal', () => {
32
+ afterEach(() => {
33
+ cleanup();
34
+ });
35
+
36
+ beforeEach(() => {
37
+ transactionStatusModal$.close();
38
+ vi.clearAllMocks();
39
+ });
40
+
41
+ it('should not render when closed', () => {
42
+ render(<TransactionStatusModal />);
43
+ expect(
44
+ screen.queryByTestId('transaction-status-modal'),
45
+ ).not.toBeInTheDocument();
46
+ });
47
+
48
+ it('should show processing state when transaction is processing', async () => {
49
+ transactionStatusModal$.open(mockTransactionArgs);
50
+ render(<TransactionStatusModal />);
51
+
52
+ await waitFor(() => {
53
+ const element = screen.queryByTestId('transaction-status-title');
54
+ expect(element).toHaveTextContent('Your purchase is processing');
55
+
56
+ const messageElement = screen.queryByTestId('transaction-status-message');
57
+ expect(messageElement).toHaveTextContent(
58
+ /It should be confirmed on the blockchain shortly/,
59
+ );
60
+ });
61
+ });
62
+
63
+ it('should show success state when transaction is successful', async () => {
64
+ mockPublicClient.waitForTransactionReceipt.mockResolvedValue({
65
+ status: 'success',
66
+ });
67
+ transactionStatusModal$.open(mockTransactionArgs);
68
+ render(<TransactionStatusModal />);
69
+
70
+ await waitFor(() => {
71
+ const element = screen.queryByTestId('transaction-status-title');
72
+ expect(element).toHaveTextContent('Your purchase has processed');
73
+
74
+ const messageElement = screen.queryByTestId('transaction-status-message');
75
+ expect(messageElement).toHaveTextContent(
76
+ /You just purchased .* It's been confirmed on the blockchain!/,
77
+ );
78
+ });
79
+ });
80
+
81
+ it('should show failed state when transaction fails', async () => {
82
+ mockPublicClient.waitForTransactionReceipt.mockRejectedValue(
83
+ new Error('Transaction failed'),
84
+ );
85
+ transactionStatusModal$.open(mockTransactionArgs);
86
+ render(<TransactionStatusModal />);
87
+
88
+ await waitFor(() => {
89
+ const element = screen.queryByTestId('transaction-status-title');
90
+ expect(element).toHaveTextContent('Your purchase has failed');
91
+
92
+ const messageElement = screen.queryByTestId('transaction-status-message');
93
+ expect(messageElement).toHaveTextContent(/Your purchase has failed/);
94
+ });
95
+ });
96
+
97
+ it('should show timeout state when transaction times out', async () => {
98
+ mockPublicClient.waitForTransactionReceipt.mockRejectedValue(
99
+ new WaitForTransactionReceiptTimeoutError({ hash: '0x123' }),
100
+ );
101
+ transactionStatusModal$.open(mockTransactionArgs);
102
+ render(<TransactionStatusModal />);
103
+
104
+ await waitFor(() => {
105
+ const element = screen.queryByTestId('transaction-status-title');
106
+ expect(element).toHaveTextContent('Your purchase takes too long');
107
+
108
+ const messageElement = screen.queryByTestId('transaction-status-message');
109
+ expect(messageElement).toHaveTextContent(/Your purchase takes too long/);
110
+ });
111
+ });
112
+
113
+ it('should call onSuccess callback when transaction succeeds', async () => {
114
+ const onSuccess = vi.fn();
115
+ mockPublicClient.waitForTransactionReceipt.mockResolvedValue({
116
+ status: 'success',
117
+ });
118
+
119
+ transactionStatusModal$.open({
120
+ ...mockTransactionArgs,
121
+ callbacks: { onSuccess },
122
+ });
123
+ render(<TransactionStatusModal />);
124
+
125
+ await waitFor(() => {
126
+ expect(onSuccess).toHaveBeenCalledWith({
127
+ hash: mockTransactionArgs.hash,
128
+ });
129
+ });
130
+ });
131
+
132
+ it('should call onError callback when transaction fails', async () => {
133
+ const onError = vi.fn();
134
+ const error = new Error('Transaction failed');
135
+ mockPublicClient.waitForTransactionReceipt.mockRejectedValue(error);
136
+
137
+ transactionStatusModal$.open({
138
+ ...mockTransactionArgs,
139
+ callbacks: { onError },
140
+ });
141
+ render(<TransactionStatusModal />);
142
+
143
+ await waitFor(() => {
144
+ expect(onError).toHaveBeenCalledWith(error);
145
+ });
146
+ });
147
+ });
@@ -0,0 +1,218 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { TransactionType } from '../../../../../../_internal/types';
3
+ import { getFormattedType } from '../util/getFormattedType';
4
+ import { getTransactionStatusModalMessage } from '../util/getMessage';
5
+ import {
6
+ getTransactionStatusModalTitle,
7
+ getTransactionStatusModalSpinnerTitle,
8
+ } from '../util/getTitle';
9
+ import type { TransactionStatus } from '../store';
10
+
11
+ describe('Transaction Status Modal Utils', () => {
12
+ describe('getFormattedType', () => {
13
+ it('should return correct format for each transaction type', () => {
14
+ expect(getFormattedType(TransactionType.TRANSFER)).toBe('transfer');
15
+ expect(getFormattedType(TransactionType.LISTING)).toBe('listing');
16
+ expect(getFormattedType(TransactionType.BUY)).toBe('purchase');
17
+ expect(getFormattedType(TransactionType.SELL)).toBe('sale');
18
+ expect(getFormattedType(TransactionType.CANCEL)).toBe('cancellation');
19
+ expect(getFormattedType(TransactionType.OFFER)).toBe('offer');
20
+ });
21
+
22
+ it('should return correct verb format when verb flag is true', () => {
23
+ expect(getFormattedType(TransactionType.TRANSFER, true)).toBe(
24
+ 'transferred',
25
+ );
26
+ expect(getFormattedType(TransactionType.LISTING, true)).toBe('listed');
27
+ expect(getFormattedType(TransactionType.BUY, true)).toBe('purchased');
28
+ expect(getFormattedType(TransactionType.SELL, true)).toBe('sold');
29
+ expect(getFormattedType(TransactionType.CANCEL, true)).toBe('cancelled');
30
+ expect(getFormattedType(TransactionType.OFFER, true)).toBe('offered');
31
+ });
32
+
33
+ it("should return 'transaction' for unknown transaction types", () => {
34
+ expect(getFormattedType('UNKNOWN' as TransactionType)).toBe(
35
+ 'transaction',
36
+ );
37
+ });
38
+ });
39
+
40
+ describe('getTransactionStatusModalMessage', () => {
41
+ const baseArgs = {
42
+ transactionType: TransactionType.BUY,
43
+ collectibleName: 'Test NFT',
44
+ };
45
+
46
+ it('should return correct message for each transaction status', () => {
47
+ expect(
48
+ getTransactionStatusModalMessage({
49
+ ...baseArgs,
50
+ transactionStatus: 'PENDING',
51
+ }),
52
+ ).toBe(
53
+ 'You just purchased Test NFT. It should be confirmed on the blockchain shortly.',
54
+ );
55
+
56
+ expect(
57
+ getTransactionStatusModalMessage({
58
+ ...baseArgs,
59
+ transactionStatus: 'SUCCESS',
60
+ }),
61
+ ).toBe(
62
+ "You just purchased Test NFT. It's been confirmed on the blockchain!",
63
+ );
64
+
65
+ expect(
66
+ getTransactionStatusModalMessage({
67
+ ...baseArgs,
68
+ transactionStatus: 'FAILED',
69
+ }),
70
+ ).toBe('Your purchase has failed.');
71
+
72
+ expect(
73
+ getTransactionStatusModalMessage({
74
+ ...baseArgs,
75
+ transactionStatus: 'TIMEOUT',
76
+ }),
77
+ ).toBe(
78
+ 'Your purchase takes too long. Click the link below to track it on the explorer.',
79
+ );
80
+ });
81
+
82
+ it('should handle order ID case', () => {
83
+ expect(
84
+ getTransactionStatusModalMessage({
85
+ ...baseArgs,
86
+ orderId: '123',
87
+ transactionStatus: 'SUCCESS',
88
+ }),
89
+ ).toBe(
90
+ "You just purchased Test NFT. It's been confirmed on the blockchain!",
91
+ );
92
+ });
93
+
94
+ it('should handle offer with price', () => {
95
+ expect(
96
+ getTransactionStatusModalMessage({
97
+ transactionType: TransactionType.OFFER,
98
+ collectibleName: 'Test NFT',
99
+ transactionStatus: 'SUCCESS',
100
+ price: {
101
+ amountRaw: '1000000000000000000',
102
+ currency: {
103
+ chainId: 1,
104
+ contractAddress: '0x0000000000000000000000000000000000000000',
105
+ name: 'Ethereum',
106
+ symbol: 'ETH',
107
+ decimals: 18,
108
+ imageUrl: 'https://ethereum.org/eth.png',
109
+ exchangeRate: 1,
110
+ defaultChainCurrency: true,
111
+ nativeCurrency: true,
112
+ createdAt: '2024-01-21T00:00:00Z',
113
+ updatedAt: '2024-01-21T00:00:00Z',
114
+ },
115
+ },
116
+ }),
117
+ ).toBe(
118
+ "You just offered 1 ETH for Test NFT. It's been confirmed on the blockchain!",
119
+ );
120
+ });
121
+
122
+ it('should hide collectible name for cancel transactions', () => {
123
+ expect(
124
+ getTransactionStatusModalMessage({
125
+ transactionType: TransactionType.CANCEL,
126
+ collectibleName: 'Test NFT',
127
+ transactionStatus: 'SUCCESS',
128
+ }),
129
+ ).toBe("You just cancelled. It's been confirmed on the blockchain!");
130
+ });
131
+ });
132
+
133
+ describe('getTransactionStatusModalTitle', () => {
134
+ const baseArgs = {
135
+ transactionType: TransactionType.BUY,
136
+ };
137
+
138
+ it('should return correct title for each transaction status', () => {
139
+ expect(
140
+ getTransactionStatusModalTitle({
141
+ ...baseArgs,
142
+ transactionStatus: 'PENDING',
143
+ }),
144
+ ).toBe('Your purchase is processing');
145
+
146
+ expect(
147
+ getTransactionStatusModalTitle({
148
+ ...baseArgs,
149
+ transactionStatus: 'SUCCESS',
150
+ }),
151
+ ).toBe('Your purchase has processed');
152
+
153
+ expect(
154
+ getTransactionStatusModalTitle({
155
+ ...baseArgs,
156
+ transactionStatus: 'FAILED',
157
+ }),
158
+ ).toBe('Your purchase has failed');
159
+
160
+ expect(
161
+ getTransactionStatusModalTitle({
162
+ ...baseArgs,
163
+ transactionStatus: 'TIMEOUT',
164
+ }),
165
+ ).toBe('Your purchase takes too long');
166
+ });
167
+
168
+ it('should handle order ID case', () => {
169
+ expect(
170
+ getTransactionStatusModalTitle({
171
+ ...baseArgs,
172
+ orderId: '123',
173
+ transactionStatus: 'SUCCESS',
174
+ }),
175
+ ).toBe('Your purchase has processed');
176
+ });
177
+
178
+ it('should return empty string when transaction type is undefined', () => {
179
+ expect(
180
+ getTransactionStatusModalTitle({
181
+ transactionType: undefined,
182
+ transactionStatus: 'SUCCESS',
183
+ }),
184
+ ).toBe('');
185
+ });
186
+ });
187
+
188
+ describe('getTransactionStatusModalSpinnerTitle', () => {
189
+ it('should return correct spinner title for each status', () => {
190
+ const statuses: TransactionStatus[] = [
191
+ 'PENDING',
192
+ 'SUCCESS',
193
+ 'FAILED',
194
+ 'TIMEOUT',
195
+ ];
196
+ const expectedTitles = {
197
+ PENDING: 'Processing transaction',
198
+ SUCCESS: 'Transaction completed',
199
+ FAILED: 'Transaction failed',
200
+ TIMEOUT: 'Taking too long',
201
+ };
202
+
203
+ for (const status of statuses) {
204
+ expect(
205
+ getTransactionStatusModalSpinnerTitle({ transactionStatus: status }),
206
+ ).toBe(expectedTitles[status]);
207
+ }
208
+ });
209
+
210
+ it('should return default title for unknown status', () => {
211
+ expect(
212
+ getTransactionStatusModalSpinnerTitle({
213
+ transactionStatus: 'UNKNOWN' as TransactionStatus,
214
+ }),
215
+ ).toBe('Processing transaction');
216
+ });
217
+ });
218
+ });
@@ -82,6 +82,12 @@ const TransactionStatusModal = observer(() => {
82
82
  orderId ? 'SUCCESS' : 'PENDING',
83
83
  );
84
84
  const queryClient = getQueryClient();
85
+ const publicClient = chainId ? getPublicRpcClient(chainId) : null;
86
+ const waitForTransactionReceiptPromise =
87
+ publicClient?.waitForTransactionReceipt({
88
+ confirmations: confirmations || TRANSACTION_CONFIRMATIONS_DEFAULT,
89
+ hash: hash || '0x',
90
+ });
85
91
 
86
92
  // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
87
93
  useEffect(() => {
@@ -148,38 +154,49 @@ const TransactionStatusModal = observer(() => {
148
154
  orderId,
149
155
  price,
150
156
  });
151
- const publicClient = chainId ? getPublicRpcClient(chainId) : null;
152
- const waitForTransactionReceiptPromise =
153
- publicClient?.waitForTransactionReceipt({
154
- confirmations: confirmations || TRANSACTION_CONFIRMATIONS_DEFAULT,
155
- hash: hash || '0x',
156
- });
157
157
 
158
158
  return (
159
159
  <Root open={transactionStatusModal$.isOpen.get()}>
160
160
  <Portal container={getProviderEl()}>
161
161
  <Overlay className={dialogOverlay} />
162
162
 
163
- <Content className={transactionStatusModalContent}>
163
+ <Content
164
+ className={transactionStatusModalContent}
165
+ data-testid="transaction-status-modal"
166
+ >
164
167
  {title ? (
165
168
  <Text
166
169
  fontSize="large"
167
170
  fontWeight="bold"
168
171
  color="text100"
169
172
  fontFamily="body"
173
+ data-testid="transaction-status-title"
170
174
  >
171
175
  {title}
172
176
  </Text>
173
177
  ) : (
174
- <Skeleton width="16" height="6" />
178
+ <Skeleton
179
+ width="16"
180
+ height="6"
181
+ data-testid="transaction-modal-title-skeleton"
182
+ />
175
183
  )}
176
184
 
177
185
  {message ? (
178
- <Text fontSize="small" color="text80" fontFamily="body">
186
+ <Text
187
+ fontSize="small"
188
+ color="text80"
189
+ fontFamily="body"
190
+ data-testid="transaction-status-message"
191
+ >
179
192
  {message}
180
193
  </Text>
181
194
  ) : (
182
- <Skeleton width="20" height="4" />
195
+ <Skeleton
196
+ width="20"
197
+ height="4"
198
+ data-testid="transaction-modal-content-skeleton"
199
+ />
183
200
  )}
184
201
 
185
202
  <TransactionPreview
@@ -35,7 +35,7 @@ export function getTransactionStatusModalMessage({
35
35
  case 'PENDING':
36
36
  return `You just ${getFormattedType(transactionType, true)}${!hideCollectibleName ? ` ${collectibleName}` : ''}. It should be confirmed on the blockchain shortly.`;
37
37
  case 'SUCCESS':
38
- return `You just ${getFormattedType(transactionType, true)}${!hideCollectibleName ? ` ${collectibleName}` : ''}. Its been confirmed on the blockchain!`;
38
+ return `You just ${getFormattedType(transactionType, true)}${!hideCollectibleName ? ` ${collectibleName}` : ''}. It's been confirmed on the blockchain!`;
39
39
  case 'FAILED':
40
40
  return `Your ${getFormattedType(transactionType)} has failed.`;
41
41
  case 'TIMEOUT':
@@ -1,5 +1,4 @@
1
1
  import { observer } from '@legendapp/state/react';
2
- import { AccountModal } from './Account';
3
2
  import { MakeOfferModal } from './MakeOfferModal/Modal';
4
3
  import { SellModal } from './SellModal/Modal';
5
4
  import SuccessfulPurchaseModal from './SuccessfulPurchaseModal';
@@ -13,7 +12,6 @@ import { BuyModal } from './BuyModal/Modal';
13
12
  export const ModalProvider = observer(() => {
14
13
  return (
15
14
  <>
16
- <AccountModal />
17
15
  <CreateListingModal />
18
16
  <MakeOfferModal />
19
17
  <TransferModal />
@@ -11,7 +11,7 @@ interface Socials {
11
11
  youtube?: string;
12
12
  }
13
13
 
14
- enum WalletOptions {
14
+ export enum WalletOptions {
15
15
  Sequence = 'sequence',
16
16
  Metamask = 'metamask',
17
17
  WalletConnect = 'walletconnect',
@@ -0,0 +1,65 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { truncateMiddle, truncateEnd, compareAddress } from '../address';
3
+
4
+ describe('address utils', () => {
5
+ describe('truncateMiddle', () => {
6
+ test('should truncate address with default parameters', () => {
7
+ const address = '0x1234567890123456789012345678901234567890';
8
+ const result = truncateMiddle(address);
9
+ expect(result).toBe('0x12345678901234567890…890');
10
+ });
11
+
12
+ test('should return full address if minPrefix + minSuffix >= 40', () => {
13
+ const address = '0x1234567890123456789012345678901234567890';
14
+ const result = truncateMiddle(address, 35, 6);
15
+ expect(result).toBe(address);
16
+ });
17
+
18
+ test('should truncate with custom prefix and suffix lengths', () => {
19
+ const address = '0x1234567890123456789012345678901234567890';
20
+ const result = truncateMiddle(address, 10, 5);
21
+ expect(result).toBe('0x1234567890…67890');
22
+ });
23
+ });
24
+
25
+ describe('truncateEnd', () => {
26
+ test('should return empty string for undefined input', () => {
27
+ expect(truncateEnd(undefined, 10)).toBe('');
28
+ });
29
+
30
+ test('should not truncate text shorter than truncateAt', () => {
31
+ const text = 'Short';
32
+ expect(truncateEnd(text, 10)).toBe('Short');
33
+ });
34
+
35
+ test('should truncate text longer than truncateAt', () => {
36
+ const text = 'This is a very long text';
37
+ expect(truncateEnd(text, 10)).toBe('This is a ...');
38
+ });
39
+
40
+ test('should truncate text equal to truncateAt', () => {
41
+ const text = '1234567890';
42
+ expect(truncateEnd(text, 10)).toBe('1234567890...');
43
+ });
44
+ });
45
+
46
+ describe('compareAddress', () => {
47
+ test('should return true for matching addresses with different cases', () => {
48
+ expect(compareAddress('0x1234567890abcdef', '0x1234567890ABCDEF')).toBe(
49
+ true,
50
+ );
51
+ });
52
+
53
+ test('should return false for different addresses', () => {
54
+ expect(compareAddress('0x1234567890abcdef', '0x1234567890abcdef1')).toBe(
55
+ false,
56
+ );
57
+ });
58
+
59
+ test('should handle undefined or empty inputs', () => {
60
+ expect(compareAddress()).toBe(true);
61
+ expect(compareAddress('', '')).toBe(true);
62
+ expect(compareAddress('0x123', '')).toBe(false);
63
+ });
64
+ });
65
+ });
@@ -0,0 +1,31 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { dateToUnixTime } from '../date';
3
+
4
+ describe('date utils', () => {
5
+ describe('dateToUnixTime', () => {
6
+ test('should convert date to unix timestamp string', () => {
7
+ const date = new Date('2024-01-01T00:00:00Z');
8
+ const result = dateToUnixTime(date);
9
+ expect(result).toBe('1704067200');
10
+ });
11
+
12
+ test('should handle current date', () => {
13
+ const now = new Date();
14
+ const result = dateToUnixTime(now);
15
+ const expectedTimestamp = Math.floor(now.getTime() / 1000).toString();
16
+ expect(result).toBe(expectedTimestamp);
17
+ });
18
+
19
+ test('should handle dates with milliseconds', () => {
20
+ const date = new Date('2024-01-01T00:00:00.999Z');
21
+ const result = dateToUnixTime(date);
22
+ expect(result).toBe('1704067200');
23
+ });
24
+
25
+ test('should handle dates before unix epoch', () => {
26
+ const date = new Date('1969-12-31T23:59:59Z');
27
+ const result = dateToUnixTime(date);
28
+ expect(result).toBe('-1');
29
+ });
30
+ });
31
+ });
@@ -0,0 +1,109 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { getPublicRpcClient } from '../get-public-rpc-client';
3
+ import { allNetworks, findNetworkConfig } from '@0xsequence/network';
4
+ import { MissingConfigError } from '../_internal/error/transaction';
5
+ import type { PublicClient } from 'viem';
6
+
7
+ describe('getPublicRpcClient', () => {
8
+ describe('successful client creation', () => {
9
+ test('should create client for mainnet', () => {
10
+ const chainId = 1;
11
+ const client = getPublicRpcClient(chainId);
12
+
13
+ expect(client).toBeDefined();
14
+ expect(client).toHaveProperty('chain');
15
+ expect(
16
+ (client as PublicClient & { chain: { id: number } }).chain.id,
17
+ ).toBe(chainId);
18
+ expect(
19
+ (client as PublicClient & { chain: { name: string } }).chain.name,
20
+ ).toBe('mainnet');
21
+ });
22
+
23
+ test('should create client for polygon', () => {
24
+ const chainId = 137;
25
+ const client = getPublicRpcClient(chainId);
26
+
27
+ expect(client).toBeDefined();
28
+ expect(
29
+ (client as PublicClient & { chain: { id: number } }).chain.id,
30
+ ).toBe(chainId);
31
+ expect(
32
+ (client as PublicClient & { chain: { name: string } }).chain.name,
33
+ ).toBe('polygon');
34
+ });
35
+
36
+ test('should set up multicall batching', () => {
37
+ const chainId = 1;
38
+ const client = getPublicRpcClient(chainId);
39
+
40
+ expect(client).toHaveProperty('batch');
41
+ expect(
42
+ (client as PublicClient & { batch: { multicall: boolean } }).batch
43
+ .multicall,
44
+ ).toBe(true);
45
+ });
46
+
47
+ test('should configure RPC URLs correctly', () => {
48
+ const chainId = 1;
49
+ const network = findNetworkConfig(allNetworks, chainId);
50
+ expect(network).toBeDefined();
51
+ const client = getPublicRpcClient(chainId);
52
+
53
+ expect(client.chain!.rpcUrls.default.http).toEqual([network!.rpcUrl]);
54
+ });
55
+
56
+ test('should set up native currency details', () => {
57
+ const chainId = 1;
58
+ const network = findNetworkConfig(allNetworks, chainId);
59
+ expect(network).toBeDefined();
60
+ const client = getPublicRpcClient(chainId);
61
+
62
+ expect(client.chain!.nativeCurrency).toEqual(network!.nativeToken);
63
+ });
64
+ });
65
+
66
+ describe('error handling', () => {
67
+ test('should throw MissingConfigError for invalid chainId', () => {
68
+ const invalidChainId = 999999;
69
+
70
+ expect(() => getPublicRpcClient(invalidChainId)).toThrow(
71
+ MissingConfigError,
72
+ );
73
+ expect(() => getPublicRpcClient(invalidChainId)).toThrow(
74
+ `Network configuration for chainId: ${invalidChainId}`,
75
+ );
76
+ });
77
+
78
+ test('should throw MissingConfigError for undefined chainId', () => {
79
+ const undefinedChainId = undefined as unknown as number;
80
+
81
+ expect(() => getPublicRpcClient(undefinedChainId)).toThrow(
82
+ `Network configuration for chainId: ${undefinedChainId}`,
83
+ );
84
+ });
85
+ });
86
+
87
+ describe('client configuration', () => {
88
+ test('should create client with correct transport configuration', () => {
89
+ const chainId = 1;
90
+ const client = getPublicRpcClient(chainId);
91
+
92
+ expect(client).toHaveProperty('transport');
93
+ expect(client.transport).toHaveProperty('request');
94
+ expect(typeof client.transport.request).toBe('function');
95
+ });
96
+
97
+ test('should create unique instances for different chains', () => {
98
+ const mainnetClient = getPublicRpcClient(1);
99
+ const polygonClient = getPublicRpcClient(137);
100
+
101
+ expect(mainnetClient).not.toBe(polygonClient);
102
+ expect(
103
+ (mainnetClient as PublicClient & { chain: { id: number } }).chain.id,
104
+ ).not.toBe(
105
+ (polygonClient as PublicClient & { chain: { id: number } }).chain.id,
106
+ );
107
+ });
108
+ });
109
+ });