@0xsequence/marketplace-sdk 0.7.0 → 0.8.1

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 (227) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.changeset/seven-doors-taste.md +5 -0
  4. package/CHANGELOG.md +13 -0
  5. package/dist/{chunk-MPBN3E54.js → chunk-2VHHJNXY.js} +3 -3
  6. package/dist/{chunk-FBUMNJQ4.js → chunk-3II5GLHE.js} +2 -2
  7. package/dist/chunk-3JU7SQVE.js +182 -0
  8. package/dist/chunk-3JU7SQVE.js.map +1 -0
  9. package/dist/{chunk-XTGMMNV5.js → chunk-A5ACY5YV.js} +2 -2
  10. package/dist/chunk-ABSYNRT5.js +128 -0
  11. package/dist/chunk-ABSYNRT5.js.map +1 -0
  12. package/dist/{chunk-XNA64MZQ.js → chunk-BCO4CYE4.js} +2 -2
  13. package/dist/{chunk-HTFORA4Q.js → chunk-BN36GABQ.js} +1883 -1010
  14. package/dist/chunk-BN36GABQ.js.map +1 -0
  15. package/dist/{chunk-4XK7XNJ7.js → chunk-BNAUZXPV.js} +73 -2
  16. package/dist/chunk-BNAUZXPV.js.map +1 -0
  17. package/dist/{chunk-Q5URKSC4.js → chunk-FMEEJFAF.js} +1 -1
  18. package/dist/{chunk-BBASZVT3.js → chunk-GBQVYNCD.js} +5 -6
  19. package/dist/chunk-GBQVYNCD.js.map +1 -0
  20. package/dist/{chunk-3AKOPSON.js → chunk-IZ44XPBH.js} +2 -9
  21. package/dist/chunk-IZ44XPBH.js.map +1 -0
  22. package/dist/{chunk-EAJ5K7QV.js → chunk-Q5RKAMYF.js} +3 -4
  23. package/dist/chunk-Q5RKAMYF.js.map +1 -0
  24. package/dist/{chunk-RBEPPVLT.js → chunk-X3QNSQER.js} +145 -355
  25. package/dist/chunk-X3QNSQER.js.map +1 -0
  26. package/dist/{index-CzTANLaA.d.ts → index-CnaFSNE9.d.ts} +6 -7
  27. package/dist/index.css +113 -31
  28. package/dist/index.css.map +1 -1
  29. package/dist/index.d.ts +2 -4
  30. package/dist/index.js +4 -4
  31. package/dist/listCollectibles-B0tbqnRd.d.ts +155 -0
  32. package/dist/react/_internal/api/index.d.ts +28 -2
  33. package/dist/react/_internal/api/index.js +3 -1
  34. package/dist/react/_internal/databeat/index.js +10 -9
  35. package/dist/react/_internal/index.d.ts +2 -3
  36. package/dist/react/_internal/index.js +4 -4
  37. package/dist/react/_internal/wagmi/index.js +2 -2
  38. package/dist/react/hooks/index.d.ts +259 -674
  39. package/dist/react/hooks/index.js +11 -20
  40. package/dist/react/hooks/options/index.d.ts +1 -2
  41. package/dist/react/hooks/options/index.js +4 -4
  42. package/dist/react/index.d.ts +7 -7
  43. package/dist/react/index.js +15 -24
  44. package/dist/react/queries/index.d.ts +25 -0
  45. package/dist/react/queries/index.js +48 -0
  46. package/dist/react/queries/index.js.map +1 -0
  47. package/dist/react/ssr/index.js +3 -3
  48. package/dist/react/ui/components/collectible-card/index.d.ts +1 -6
  49. package/dist/react/ui/components/collectible-card/index.js +13 -12
  50. package/dist/react/ui/components/marketplace-logos/index.js +1 -1
  51. package/dist/react/ui/icons/index.js +6 -6
  52. package/dist/react/ui/index.d.ts +18 -22
  53. package/dist/react/ui/index.js +13 -12
  54. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +6 -11
  55. package/dist/react/ui/modals/_internal/components/actionModal/index.js +10 -9
  56. package/dist/types/index.js +2 -2
  57. package/dist/{types-Ct1uCT3M.d.ts → types-o_pKUpQG.d.ts} +2 -5
  58. package/dist/utils/index.d.ts +1 -5
  59. package/dist/utils/index.js +4 -4
  60. package/package.json +22 -16
  61. package/src/react/_internal/api/__mocks__/indexer.msw.ts +3 -1
  62. package/src/react/_internal/api/__mocks__/marketplace.msw.ts +1 -1
  63. package/src/react/_internal/api/__mocks__/metadata.msw.ts +14 -12
  64. package/src/react/_internal/api/index.ts +1 -0
  65. package/src/react/_internal/api/laos-api.ts +103 -0
  66. package/src/react/_internal/api/zod-schema.ts +3 -3
  67. package/src/react/_internal/types.ts +1 -10
  68. package/src/react/_internal/wallet/__tests__/wallet.test.ts +43 -0
  69. package/src/react/_internal/wallet/useWallet.ts +6 -3
  70. package/src/react/hooks/__tests__/useAutoSelectFeeOption.test.tsx +1 -1
  71. package/src/react/hooks/__tests__/useCancelOrder.test.tsx +1 -1
  72. package/src/react/hooks/__tests__/useCancelTransactionSteps.test.tsx +1 -1
  73. package/src/react/hooks/__tests__/useCollectible.test.tsx +2 -2
  74. package/src/react/hooks/__tests__/useCollection.test.tsx +2 -2
  75. package/src/react/hooks/__tests__/useComparePrices.test.tsx +1 -1
  76. package/src/react/hooks/__tests__/useConvertPriceToUSD.test.tsx +1 -1
  77. package/src/react/hooks/__tests__/useCountListingsForCollectible.test.tsx +1 -1
  78. package/src/react/hooks/__tests__/useCountOfCollectables.test.tsx +2 -2
  79. package/src/react/hooks/__tests__/useCountOffersForCollectible.test.tsx +1 -1
  80. package/src/react/hooks/__tests__/useCurrencies.test.tsx +2 -2
  81. package/src/react/hooks/__tests__/useCurrency.test.tsx +2 -2
  82. package/src/react/hooks/__tests__/useFilters.test.tsx +2 -2
  83. package/src/react/hooks/__tests__/useFloorOrder.test.tsx +2 -2
  84. package/src/react/hooks/__tests__/useGenerateCancelTransaction.test.tsx +1 -1
  85. package/src/react/hooks/__tests__/useGenerateListingTransaction.test.tsx +1 -1
  86. package/src/react/hooks/__tests__/useGenerateOfferTransaction.test.tsx +1 -1
  87. package/src/react/hooks/__tests__/useGenerateSellTransaction.test.tsx +1 -1
  88. package/src/react/hooks/__tests__/useListCollectibleActivities.test.tsx +2 -2
  89. package/src/react/hooks/__tests__/useListCollectibles.test.tsx +3 -2
  90. package/src/react/hooks/__tests__/useListCollectiblesPaginated.test.tsx +1 -1
  91. package/src/react/hooks/__tests__/useListCollectionActivities.test.tsx +1 -1
  92. package/src/react/hooks/__tests__/useListListingsForCollectible.test.tsx +1 -1
  93. package/src/react/hooks/__tests__/useListOffersForCollectible.test.tsx +1 -1
  94. package/src/react/hooks/__tests__/useLowestListing.test.tsx +1 -1
  95. package/src/react/hooks/__tests__/useRoyalty.test.tsx +1 -2
  96. package/src/react/hooks/index.ts +0 -1
  97. package/src/react/hooks/options/collectionOptions.ts +2 -3
  98. package/src/react/hooks/useAutoSelectFeeOption.tsx +1 -1
  99. package/src/react/hooks/useCancelOrder.tsx +3 -3
  100. package/src/react/hooks/useCancelTransactionSteps.tsx +1 -1
  101. package/src/react/hooks/useCheckoutOptions.tsx +1 -2
  102. package/src/react/hooks/useCollectible.tsx +2 -3
  103. package/src/react/hooks/useCollectionBalanceDetails.tsx +1 -2
  104. package/src/react/hooks/useComparePrices.tsx +2 -9
  105. package/src/react/hooks/useConvertPriceToUSD.tsx +1 -4
  106. package/src/react/hooks/useCountListingsForCollectible.tsx +1 -2
  107. package/src/react/hooks/useCountOfCollectables.tsx +1 -2
  108. package/src/react/hooks/useCountOffersForCollectible.tsx +1 -2
  109. package/src/react/hooks/useCurrencies.tsx +1 -4
  110. package/src/react/hooks/useCurrency.tsx +3 -8
  111. package/src/react/hooks/useFilters.tsx +5 -4
  112. package/src/react/hooks/useFloorOrder.tsx +1 -2
  113. package/src/react/hooks/useGenerateCancelTransaction.tsx +3 -6
  114. package/src/react/hooks/useGenerateListingTransaction.tsx +2 -3
  115. package/src/react/hooks/useGenerateOfferTransaction.tsx +2 -3
  116. package/src/react/hooks/useGenerateSellTransaction.tsx +3 -6
  117. package/src/react/hooks/useHighestOffer.tsx +1 -1
  118. package/src/react/hooks/useListCollectibles.tsx +33 -61
  119. package/src/react/hooks/useListCollectiblesPaginated.tsx +2 -6
  120. package/src/react/hooks/useListListingsForCollectible.tsx +1 -2
  121. package/src/react/hooks/useListOffersForCollectible.tsx +1 -2
  122. package/src/react/hooks/useLowestListing.tsx +1 -2
  123. package/src/react/hooks/useRoyalty.tsx +3 -8
  124. package/src/react/hooks/useTransferTokens.tsx +2 -2
  125. package/src/react/queries/balanceOfCollectible.ts +9 -32
  126. package/src/react/queries/getTokenSupplies.ts +38 -0
  127. package/src/react/queries/index.ts +5 -0
  128. package/src/react/queries/listCollectibles.ts +96 -0
  129. package/src/react/ui/components/_internals/action-button/ActionButton.tsx +1 -1
  130. package/src/react/ui/components/_internals/action-button/__tests__/ActionButton.test.tsx +1 -1
  131. package/src/react/ui/components/_internals/action-button/components/NonOwnerActions.tsx +4 -3
  132. package/src/react/ui/components/_internals/action-button/components/OwnerActions.tsx +1 -1
  133. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +2 -3
  134. package/src/react/ui/components/collectible-card/__tests__/CollectibleCard.test.tsx +1 -1
  135. package/src/react/ui/modals/BuyModal/ERC1155QuantityModal.tsx +127 -0
  136. package/src/react/ui/modals/BuyModal/Modal.tsx +70 -85
  137. package/src/react/ui/modals/BuyModal/__tests__/Modal.test.tsx +85 -226
  138. package/src/react/ui/modals/BuyModal/__tests__/Modal1155.test.tsx +140 -0
  139. package/src/react/ui/modals/BuyModal/__tests__/store.test.ts +67 -76
  140. package/src/react/ui/modals/BuyModal/hooks/__tests__/useCheckoutOptions.test.tsx +1 -60
  141. package/src/react/ui/modals/BuyModal/hooks/__tests__/useFees.test.tsx +1 -1
  142. package/src/react/ui/modals/BuyModal/hooks/useCheckoutOptions.ts +29 -13
  143. package/src/react/ui/modals/BuyModal/hooks/useLoadData.ts +26 -21
  144. package/src/react/ui/modals/BuyModal/hooks/usePaymentModalParams.ts +200 -0
  145. package/src/react/ui/modals/BuyModal/index.tsx +4 -14
  146. package/src/react/ui/modals/BuyModal/store.ts +71 -76
  147. package/src/react/ui/modals/CreateListingModal/Modal.tsx +71 -7
  148. package/src/react/ui/modals/CreateListingModal/__tests__/Modal.test.tsx +2 -2
  149. package/src/react/ui/modals/CreateListingModal/hooks/useCreateListing.tsx +1 -1
  150. package/src/react/ui/modals/CreateListingModal/hooks/useGetTokenApproval.ts +1 -1
  151. package/src/react/ui/modals/CreateListingModal/hooks/useTransactionSteps.tsx +9 -5
  152. package/src/react/ui/modals/CreateListingModal/store.ts +7 -2
  153. package/src/react/ui/modals/MakeOfferModal/Modal.tsx +103 -6
  154. package/src/react/ui/modals/MakeOfferModal/__tests__/Modal.test.tsx +1 -1
  155. package/src/react/ui/modals/MakeOfferModal/hooks/useGetTokenApproval.tsx +1 -1
  156. package/src/react/ui/modals/MakeOfferModal/hooks/useMakeOffer.tsx +1 -1
  157. package/src/react/ui/modals/MakeOfferModal/hooks/useTransactionSteps.tsx +8 -4
  158. package/src/react/ui/modals/MakeOfferModal/store.ts +5 -3
  159. package/src/react/ui/modals/SellModal/Modal.tsx +76 -4
  160. package/src/react/ui/modals/SellModal/__tests__/Modal.test.tsx +1 -1
  161. package/src/react/ui/modals/SellModal/hooks/useGetTokenApproval.tsx +1 -1
  162. package/src/react/ui/modals/SellModal/hooks/useSell.tsx +1 -1
  163. package/src/react/ui/modals/SellModal/hooks/useTransactionSteps.tsx +16 -8
  164. package/src/react/ui/modals/SellModal/store.ts +5 -3
  165. package/src/react/ui/modals/TransferModal/_store.ts +15 -3
  166. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/_components/TokenQuantityInput.tsx +58 -0
  167. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/_components/TransferButton.tsx +56 -0
  168. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/_components/WalletAddressInput.tsx +50 -0
  169. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/index.tsx +94 -66
  170. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/useHandleTransfer.tsx +22 -14
  171. package/src/react/ui/modals/TransferModal/index.tsx +72 -38
  172. package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +43 -42
  173. package/src/react/ui/modals/_internal/components/actionModal/store.ts +1 -2
  174. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +2 -2
  175. package/src/react/ui/modals/_internal/components/expirationDateSelect/index.tsx +9 -1
  176. package/src/react/ui/modals/_internal/components/floorPriceText/index.tsx +27 -12
  177. package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +1 -1
  178. package/src/react/ui/modals/_internal/components/priceInput/index.tsx +19 -3
  179. package/src/react/ui/modals/_internal/components/quantityInput/index.tsx +3 -0
  180. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/_components/ActionButtons.tsx +60 -0
  181. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/_components/BalanceIndicator.tsx +30 -0
  182. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/index.tsx +126 -0
  183. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/store.ts +25 -0
  184. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/useWaasFeeOptionManager.tsx +74 -0
  185. package/src/react/ui/modals/_internal/components/switchChainModal/index.tsx +1 -2
  186. package/src/react/ui/modals/_internal/components/switchChainModal/store.ts +1 -2
  187. package/src/react/ui/modals/_internal/components/tokenPreview/index.tsx +1 -1
  188. package/src/react/ui/modals/_internal/components/transaction-footer/index.tsx +4 -7
  189. package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +1 -1
  190. package/src/react/ui/modals/_internal/components/transactionPreview/index.tsx +1 -1
  191. package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/TransactionStatusModal.test.tsx +1 -1
  192. package/src/react/ui/modals/_internal/components/transactionStatusModal/hooks/useTransactionStatus.ts +1 -1
  193. package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +6 -1
  194. package/src/react/ui/modals/_internal/components/transactionStatusModal/store.ts +2 -2
  195. package/src/react/ui/modals/_internal/components/waasFeeOptionsSelect/WaasFeeOptionsSelect.tsx +10 -31
  196. package/src/react/ui/modals/_internal/hooks/useSelectWaasFeeOptions.ts +53 -0
  197. package/src/react/ui/modals/_internal/types.ts +2 -1
  198. package/src/types/waas-types.ts +38 -0
  199. package/src/utils/network.ts +2 -4
  200. package/test/const.ts +1 -1
  201. package/test/setup.ts +10 -0
  202. package/test/test-utils.tsx +31 -5
  203. package/tsconfig.tsbuildinfo +1 -1
  204. package/dist/chunk-3AKOPSON.js.map +0 -1
  205. package/dist/chunk-4XK7XNJ7.js.map +0 -1
  206. package/dist/chunk-BBASZVT3.js.map +0 -1
  207. package/dist/chunk-EAJ5K7QV.js.map +0 -1
  208. package/dist/chunk-HTFORA4Q.js.map +0 -1
  209. package/dist/chunk-OFY7OFTL.js +0 -458
  210. package/dist/chunk-OFY7OFTL.js.map +0 -1
  211. package/dist/chunk-RBEPPVLT.js.map +0 -1
  212. package/src/react/hooks/__tests__/useGenerateBuyTransaction.test.tsx +0 -172
  213. package/src/react/hooks/useGenerateBuyTransaction.tsx +0 -80
  214. package/src/react/ui/modals/BuyModal/hooks/__tests__/useBuyCollectable.test.tsx +0 -349
  215. package/src/react/ui/modals/BuyModal/hooks/__tests__/useLoadData.test.tsx +0 -185
  216. package/src/react/ui/modals/BuyModal/hooks/useBuyCollectable.ts +0 -170
  217. package/src/react/ui/modals/BuyModal/modals/CheckoutModal.tsx +0 -47
  218. package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +0 -140
  219. package/src/react/ui/modals/BuyModal/modals/__tests__/CheckoutModal.test.tsx +0 -162
  220. package/src/react/ui/modals/BuyModal/modals/__tests__/Modal1155.test.tsx +0 -327
  221. package/src/react/ui/modals/_internal/components/waasFeeOptionsBox/index.tsx +0 -124
  222. package/src/react/ui/modals/_internal/components/waasFeeOptionsBox/store.ts +0 -12
  223. /package/dist/{chunk-MPBN3E54.js.map → chunk-2VHHJNXY.js.map} +0 -0
  224. /package/dist/{chunk-FBUMNJQ4.js.map → chunk-3II5GLHE.js.map} +0 -0
  225. /package/dist/{chunk-XTGMMNV5.js.map → chunk-A5ACY5YV.js.map} +0 -0
  226. /package/dist/{chunk-XNA64MZQ.js.map → chunk-BCO4CYE4.js.map} +0 -0
  227. /package/dist/{chunk-Q5URKSC4.js.map → chunk-FMEEJFAF.js.map} +0 -0
@@ -1,18 +1,31 @@
1
1
  'use client';
2
2
 
3
+ import { getNetwork } from '@0xsequence/connect';
4
+ import { NetworkType } from '@0xsequence/network';
3
5
  import { Show, observer } from '@legendapp/state/react';
4
6
  import { useState } from 'react';
5
7
  import { parseUnits } from 'viem';
8
+ import type { FeeOption } from '../../../../types/waas-types';
6
9
  import { dateToUnixTime } from '../../../../utils/date';
7
10
  import { ContractType } from '../../../_internal';
8
- import { useCollectible, useCollection, useCurrencies } from '../../../hooks';
11
+ import { useWallet } from '../../../_internal/wallet/useWallet';
12
+ import {
13
+ useCollectible,
14
+ useCollection,
15
+ useCurrencies,
16
+ useLowestListing,
17
+ } from '../../../hooks';
18
+ import { useBuyModal } from '../BuyModal';
9
19
  import { ActionModal } from '../_internal/components/actionModal/ActionModal';
10
20
  import { ErrorModal } from '../_internal/components/actionModal/ErrorModal';
11
21
  import ExpirationDateSelect from '../_internal/components/expirationDateSelect';
12
22
  import FloorPriceText from '../_internal/components/floorPriceText';
13
23
  import PriceInput from '../_internal/components/priceInput';
14
24
  import QuantityInput from '../_internal/components/quantityInput';
25
+ import SelectWaasFeeOptions from '../_internal/components/selectWaasFeeOptions';
26
+ import { selectWaasFeeOptions$ } from '../_internal/components/selectWaasFeeOptions/store';
15
27
  import TokenPreview from '../_internal/components/tokenPreview';
28
+ import { useSelectWaasFeeOptions } from '../_internal/hooks/useSelectWaasFeeOptions';
16
29
  import { useMakeOffer } from './hooks/useMakeOffer';
17
30
  import { makeOfferModal$ } from './store';
18
31
 
@@ -43,6 +56,20 @@ const Modal = observer(() => {
43
56
  collectionAddress,
44
57
  collectibleId,
45
58
  });
59
+ const { wallet } = useWallet();
60
+ const isProcessing = makeOfferModal$.offerIsBeingProcessed.get();
61
+
62
+ const {
63
+ shouldHideActionButton: shouldHideOfferButton,
64
+ waasFeeOptionsShown,
65
+ getActionLabel,
66
+ } = useSelectWaasFeeOptions({
67
+ chainId,
68
+ isProcessing,
69
+ feeOptionsVisible: selectWaasFeeOptions$.isVisible.get(),
70
+ selectedFeeOption:
71
+ selectWaasFeeOptions$.selectedFeeOption.get() as FeeOption,
72
+ });
46
73
 
47
74
  const {
48
75
  data: collection,
@@ -85,6 +112,17 @@ const Modal = observer(() => {
85
112
  steps$: steps$,
86
113
  });
87
114
 
115
+ const buyModal = useBuyModal(callbacks);
116
+
117
+ const { data: lowestListing } = useLowestListing({
118
+ tokenId: collectibleId,
119
+ chainId,
120
+ collectionAddress,
121
+ filters: {
122
+ currencies: [offerPrice.currency.contractAddress],
123
+ },
124
+ });
125
+
88
126
  if (collectableIsError || collectionIsError || currenciesIsError) {
89
127
  return (
90
128
  <ErrorModal
@@ -108,6 +146,29 @@ const Modal = observer(() => {
108
146
  );
109
147
  }
110
148
 
149
+ const handleMakeOffer = async () => {
150
+ makeOfferModal$.offerIsBeingProcessed.set(true);
151
+
152
+ try {
153
+ if (wallet?.isWaaS) {
154
+ selectWaasFeeOptions$.isVisible.set(true);
155
+ }
156
+
157
+ await makeOffer({
158
+ isTransactionExecuting: wallet?.isWaaS
159
+ ? getNetwork(Number(chainId)).type !== NetworkType.TESTNET
160
+ : false,
161
+ });
162
+ } catch (error) {
163
+ console.error('Make offer failed:', error);
164
+ } finally {
165
+ makeOfferModal$.offerIsBeingProcessed.set(false);
166
+ steps$.transaction.isExecuting.set(false);
167
+ }
168
+ };
169
+
170
+ const offerCtaLabel = getActionLabel('Make offer');
171
+
111
172
  const ctas = [
112
173
  {
113
174
  label: 'Approve TOKEN',
@@ -123,9 +184,11 @@ const Modal = observer(() => {
123
184
  !offerPriceChanged,
124
185
  },
125
186
  {
126
- label: 'Make offer',
127
- onClick: () => makeOffer(),
128
- pending: steps$.transaction.isExecuting.get(),
187
+ label: offerCtaLabel,
188
+ onClick: () => handleMakeOffer(),
189
+ pending:
190
+ steps$?.transaction.isExecuting.get() ||
191
+ makeOfferModal$.offerIsBeingProcessed.get(),
129
192
  disabled:
130
193
  steps$.approval.isExecuting.get() ||
131
194
  steps$.approval.exist.get() ||
@@ -141,11 +204,16 @@ const Modal = observer(() => {
141
204
  <ActionModal
142
205
  isOpen={makeOfferModal$.isOpen.get()}
143
206
  chainId={Number(chainId)}
144
- onClose={() => makeOfferModal$.close()}
207
+ onClose={() => {
208
+ makeOfferModal$.close();
209
+ selectWaasFeeOptions$.hide();
210
+ steps$.transaction.isExecuting.set(false);
211
+ }}
145
212
  title="Make an offer"
146
213
  ctas={ctas}
147
214
  modalLoading={modalLoading}
148
215
  spinnerContainerClassname="h-[188px]"
216
+ hideCtas={shouldHideOfferButton}
149
217
  >
150
218
  <TokenPreview
151
219
  collectionName={collection?.name}
@@ -164,6 +232,7 @@ const Modal = observer(() => {
164
232
  enabled: true,
165
233
  callback: (state) => setInsufficientBalance(state),
166
234
  }}
235
+ disabled={shouldHideOfferButton}
167
236
  />
168
237
 
169
238
  {collection?.type === ContractType.ERC1155 && (
@@ -172,6 +241,7 @@ const Modal = observer(() => {
172
241
  $invalidQuantity={makeOfferModal$.invalidQuantity}
173
242
  decimals={collectible?.decimals || 0}
174
243
  maxQuantity={String(Number.MAX_SAFE_INTEGER)}
244
+ disabled={shouldHideOfferButton}
175
245
  />
176
246
  )}
177
247
 
@@ -183,9 +253,36 @@ const Modal = observer(() => {
183
253
  chainId={chainId}
184
254
  collectionAddress={collectionAddress}
185
255
  price={offerPrice}
256
+ onBuyNow={() => {
257
+ makeOfferModal$.close();
258
+
259
+ if (lowestListing?.order) {
260
+ buyModal.show({
261
+ chainId,
262
+ collectionAddress,
263
+ collectibleId,
264
+ orderId: lowestListing.order.orderId,
265
+ marketplace: lowestListing.order.marketplace,
266
+ });
267
+ }
268
+ }}
186
269
  />
187
270
  )}
188
- <ExpirationDateSelect $date={makeOfferModal$.expiry} />
271
+ <ExpirationDateSelect
272
+ $date={makeOfferModal$.expiry}
273
+ disabled={shouldHideOfferButton}
274
+ />
275
+
276
+ {waasFeeOptionsShown && (
277
+ <SelectWaasFeeOptions
278
+ chainId={Number(chainId)}
279
+ onCancel={() => {
280
+ makeOfferModal$.offerIsBeingProcessed.set(false);
281
+ steps$.transaction.isExecuting.set(false);
282
+ }}
283
+ titleOnConfirm="Processing offer..."
284
+ />
285
+ )}
189
286
  </ActionModal>
190
287
  </>
191
288
  );
@@ -23,7 +23,7 @@ vi.mock('@0xsequence/kit', () => ({
23
23
 
24
24
  const defaultArgs = {
25
25
  collectionAddress: zeroAddress,
26
- chainId: '1',
26
+ chainId: 1,
27
27
  collectibleId: '1',
28
28
  };
29
29
 
@@ -13,7 +13,7 @@ import { useWallet } from '../../../../_internal/wallet/useWallet';
13
13
  import { useConfig } from '../../../../hooks/useConfig';
14
14
 
15
15
  export interface UseGetTokenApprovalDataArgs {
16
- chainId: string;
16
+ chainId: number;
17
17
  tokenId: string;
18
18
  collectionAddress: string;
19
19
  currencyAddress: string;
@@ -12,7 +12,7 @@ import { useTransactionSteps } from './useTransactionSteps';
12
12
 
13
13
  interface UseMakeOfferArgs {
14
14
  offerInput: OfferInput;
15
- chainId: string;
15
+ chainId: number;
16
16
  collectionAddress: string;
17
17
  orderbookKind?: OrderbookKind;
18
18
  callbacks?: ModalCallbacks;
@@ -26,7 +26,7 @@ export type ExecutionState = 'approval' | 'offer' | null;
26
26
 
27
27
  interface UseTransactionStepsArgs {
28
28
  offerInput: OfferInput;
29
- chainId: string;
29
+ chainId: number;
30
30
  collectionAddress: string;
31
31
  orderbookKind?: OrderbookKind;
32
32
  callbacks?: ModalCallbacks;
@@ -111,11 +111,15 @@ export const useTransactionSteps = ({
111
111
  }
112
112
  };
113
113
 
114
- const makeOffer = async () => {
114
+ const makeOffer = async ({
115
+ isTransactionExecuting,
116
+ }: {
117
+ isTransactionExecuting: boolean;
118
+ }) => {
115
119
  if (!wallet) return;
116
120
 
117
121
  try {
118
- steps$.transaction.isExecuting.set(true);
122
+ steps$.transaction.isExecuting.set(isTransactionExecuting);
119
123
  const steps = await getOfferSteps();
120
124
  const transactionStep = steps?.find(
121
125
  (step) => step.id === StepType.createOffer,
@@ -192,7 +196,7 @@ export const useTransactionSteps = ({
192
196
  collectionAddress,
193
197
  currencyAddress: offerInput.offer.currencyAddress,
194
198
  currencySymbol: currency?.symbol || '',
195
- chainId,
199
+ chainId: chainId.toString(),
196
200
  txnHash: hash || '',
197
201
  },
198
202
  nums: {
@@ -15,11 +15,12 @@ type MakeOfferState = BaseModalState & {
15
15
  invalidQuantity: boolean;
16
16
  collectionType?: CollectionType;
17
17
  steps: TransactionSteps;
18
+ offerIsBeingProcessed: boolean;
18
19
  };
19
20
 
20
21
  export type OpenMakeOfferModalArgs = {
21
22
  collectionAddress: Hex;
22
- chainId: string;
23
+ chainId: number;
23
24
  collectibleId: string;
24
25
  orderbookKind?: OrderbookKind;
25
26
  callbacks?: ModalCallbacks;
@@ -55,7 +56,7 @@ const steps = {
55
56
  const initialState: MakeOfferState = {
56
57
  isOpen: false,
57
58
  collectionAddress: '' as Hex,
58
- chainId: '',
59
+ chainId: 0,
59
60
  collectibleId: '',
60
61
  orderbookKind: undefined,
61
62
  callbacks: undefined,
@@ -66,6 +67,7 @@ const initialState: MakeOfferState = {
66
67
  expiry: new Date(addDays(new Date(), 7).toJSON()),
67
68
  collectionType: undefined,
68
69
  steps: { ...steps },
70
+ offerIsBeingProcessed: false,
69
71
  };
70
72
 
71
73
  const actions: Actions = {
@@ -82,7 +84,7 @@ const actions: Actions = {
82
84
  makeOfferModal$.set({ ...initialState, ...actions });
83
85
  makeOfferModal$.steps.set({ ...steps });
84
86
  makeOfferModal$.offerPrice.set({ ...offerPrice });
85
- makeOfferModal$.steps.set({ ...steps });
87
+ makeOfferModal$.offerIsBeingProcessed.set(false);
86
88
  },
87
89
  };
88
90
 
@@ -1,16 +1,25 @@
1
+ 'use client';
2
+
3
+ import { getNetwork } from '@0xsequence/connect';
4
+ import { NetworkType } from '@0xsequence/network';
1
5
  import { Show, observer } from '@legendapp/state/react';
2
6
  import { parseUnits } from 'viem';
3
7
  import type { Price } from '../../../../types';
8
+ import type { FeeOption } from '../../../../types/waas-types';
4
9
  import type { MarketplaceKind } from '../../../_internal/api/marketplace.gen';
10
+ import { useWallet } from '../../../_internal/wallet/useWallet';
5
11
  import { useCollection, useCurrency } from '../../../hooks';
6
12
  import {
7
13
  ActionModal,
8
14
  type ActionModalProps,
9
15
  } from '../_internal/components/actionModal/ActionModal';
10
16
  import { ErrorModal } from '../_internal/components/actionModal/ErrorModal';
17
+ import SelectWaasFeeOptions from '../_internal/components/selectWaasFeeOptions';
18
+ import { selectWaasFeeOptions$ } from '../_internal/components/selectWaasFeeOptions/store';
11
19
  import TokenPreview from '../_internal/components/tokenPreview';
12
20
  import TransactionDetails from '../_internal/components/transactionDetails';
13
21
  import TransactionHeader from '../_internal/components/transactionHeader';
22
+ import { useSelectWaasFeeOptions } from '../_internal/hooks/useSelectWaasFeeOptions';
14
23
  import { useSell } from './hooks/useSell';
15
24
  import { sellModal$ } from './store';
16
25
 
@@ -43,6 +52,20 @@ const Modal = observer(() => {
43
52
  chainId,
44
53
  currencyAddress: order?.priceCurrencyAddress ?? '',
45
54
  });
55
+ const { wallet } = useWallet();
56
+ const feeOptionsVisible = selectWaasFeeOptions$.isVisible.get();
57
+ const network = getNetwork(Number(chainId));
58
+ const isTestnet = network.type === NetworkType.TESTNET;
59
+ const isProcessing = sellModal$.sellIsBeingProcessed.get();
60
+ const isWaaS = wallet?.isWaaS;
61
+ const { shouldHideActionButton: shouldHideSellButton } =
62
+ useSelectWaasFeeOptions({
63
+ chainId,
64
+ isProcessing,
65
+ feeOptionsVisible: selectWaasFeeOptions$.isVisible.get(),
66
+ selectedFeeOption:
67
+ selectWaasFeeOptions$.selectedFeeOption.get() as FeeOption,
68
+ });
46
69
 
47
70
  const { isLoading, executeApproval, sell } = useSell({
48
71
  collectionAddress,
@@ -82,6 +105,32 @@ const Modal = observer(() => {
82
105
  );
83
106
  }
84
107
 
108
+ const handleSell = async () => {
109
+ sellModal$.sellIsBeingProcessed.set(true);
110
+
111
+ try {
112
+ if (wallet?.isWaaS) {
113
+ selectWaasFeeOptions$.isVisible.set(true);
114
+ }
115
+
116
+ await sell({
117
+ isTransactionExecuting: wallet?.isWaaS ? !isTestnet : false,
118
+ });
119
+ } catch (error) {
120
+ console.error('Sell failed:', error);
121
+ } finally {
122
+ sellModal$.sellIsBeingProcessed.set(false);
123
+ steps$.transaction.isExecuting.set(false);
124
+ }
125
+ };
126
+
127
+ // if it's testnet, we don't need to show the fee options
128
+ const sellCtaLabel = isProcessing
129
+ ? isWaaS && !isTestnet
130
+ ? 'Loading fee options'
131
+ : 'Accept'
132
+ : 'Accept';
133
+
85
134
  const ctas = [
86
135
  {
87
136
  label: 'Approve TOKEN',
@@ -92,9 +141,11 @@ const Modal = observer(() => {
92
141
  disabled: isLoading || order?.quantityRemaining === '0',
93
142
  },
94
143
  {
95
- label: 'Accept',
96
- onClick: () => sell(),
97
- pending: steps$.transaction.isExecuting.get(),
144
+ label: sellCtaLabel,
145
+ onClick: () => handleSell(),
146
+ pending:
147
+ steps$?.transaction.isExecuting.get() ||
148
+ sellModal$.sellIsBeingProcessed.get(),
98
149
  disabled:
99
150
  isLoading ||
100
151
  steps$.approval.isExecuting.get() ||
@@ -103,15 +154,25 @@ const Modal = observer(() => {
103
154
  },
104
155
  ] satisfies ActionModalProps['ctas'];
105
156
 
157
+ const showWaasFeeOptions =
158
+ wallet?.isWaaS &&
159
+ sellModal$.sellIsBeingProcessed.get() &&
160
+ feeOptionsVisible;
161
+
106
162
  return (
107
163
  <ActionModal
108
164
  isOpen={sellModal$.isOpen.get()}
109
165
  chainId={Number(chainId)}
110
- onClose={sellModal$.close}
166
+ onClose={() => {
167
+ sellModal$.close();
168
+ selectWaasFeeOptions$.hide();
169
+ steps$.transaction.isExecuting.set(false);
170
+ }}
111
171
  title="You have an offer"
112
172
  ctas={ctas}
113
173
  modalLoading={modalLoading}
114
174
  spinnerContainerClassname="h-[104px]"
175
+ hideCtas={shouldHideSellButton}
115
176
  >
116
177
  <TransactionHeader
117
178
  title="Offer received"
@@ -139,6 +200,17 @@ const Modal = observer(() => {
139
200
  }
140
201
  currencyImageUrl={currency?.imageUrl}
141
202
  />
203
+
204
+ {showWaasFeeOptions && (
205
+ <SelectWaasFeeOptions
206
+ chainId={Number(chainId)}
207
+ onCancel={() => {
208
+ sellModal$.sellIsBeingProcessed.set(false);
209
+ steps$.transaction.isExecuting.set(false);
210
+ }}
211
+ titleOnConfirm="Accepting offer..."
212
+ />
213
+ )}
142
214
  </ActionModal>
143
215
  );
144
216
  });
@@ -23,7 +23,7 @@ const mockOrder = {
23
23
 
24
24
  const mockModalProps = {
25
25
  collectionAddress: '0x123',
26
- chainId: '1',
26
+ chainId: 1,
27
27
  tokenId: '1',
28
28
  order: mockOrder,
29
29
  } satisfies OpenSellModalArgs;
@@ -11,7 +11,7 @@ import { useConfig } from '../../../../hooks/useConfig';
11
11
  import { useFees } from '../../BuyModal/hooks/useFees';
12
12
 
13
13
  export interface UseGetTokenApprovalDataArgs {
14
- chainId: string;
14
+ chainId: number;
15
15
  collectionAddress: string;
16
16
  marketplace: MarketplaceKind;
17
17
  ordersData: Array<OrderData>;
@@ -16,7 +16,7 @@ export type SellOrder = {
16
16
 
17
17
  interface UseSellArgs {
18
18
  collectibleId: string;
19
- chainId: string;
19
+ chainId: number;
20
20
  collectionAddress: string;
21
21
  marketplace: MarketplaceKind;
22
22
  ordersData: Array<SellOrder>;
@@ -31,7 +31,7 @@ export type ExecutionState = 'approval' | 'sell' | null;
31
31
 
32
32
  interface UseTransactionStepsArgs {
33
33
  collectibleId: string;
34
- chainId: string;
34
+ chainId: number;
35
35
  collectionAddress: string;
36
36
  marketplace: MarketplaceKind;
37
37
  ordersData: Array<SellOrder>;
@@ -57,12 +57,12 @@ export const useTransactionSteps = ({
57
57
  const analytics = useAnalytics();
58
58
 
59
59
  const { amount, receiver } = useFees({
60
- chainId: Number(chainId),
60
+ chainId,
61
61
  collectionAddress: collectionAddress,
62
62
  });
63
63
 
64
64
  const { data: currencies } = useCurrencies({
65
- chainId: Number(chainId),
65
+ chainId,
66
66
  });
67
67
  const { generateSellTransactionAsync, isPending: generatingSteps } =
68
68
  useGenerateSellTransaction({
@@ -124,11 +124,15 @@ export const useTransactionSteps = ({
124
124
  }
125
125
  };
126
126
 
127
- const sell = async () => {
127
+ const sell = async ({
128
+ isTransactionExecuting,
129
+ }: {
130
+ isTransactionExecuting: boolean;
131
+ }) => {
128
132
  if (!wallet) return;
129
133
 
130
134
  try {
131
- steps$.transaction.isExecuting.set(true);
135
+ steps$.transaction.isExecuting.set(isTransactionExecuting);
132
136
  const steps = await getSellSteps();
133
137
  const transactionStep = steps?.find((step) => step.id === StepType.sell);
134
138
  const signatureStep = steps?.find(
@@ -196,7 +200,7 @@ export const useTransactionSteps = ({
196
200
  collectionAddress,
197
201
  currencyAddress: ordersData[0].currencyAddress,
198
202
  currencySymbol,
199
- chainId,
203
+ chainId: chainId.toString(),
200
204
  txnHash: hash || '',
201
205
  },
202
206
  nums: {
@@ -216,7 +220,9 @@ export const useTransactionSteps = ({
216
220
 
217
221
  const executeTransaction = async ({
218
222
  transactionStep,
219
- }: { transactionStep: Step }) => {
223
+ }: {
224
+ transactionStep: Step;
225
+ }) => {
220
226
  if (!wallet) return;
221
227
 
222
228
  const hash = await wallet.handleSendTransactionStep(
@@ -229,7 +235,9 @@ export const useTransactionSteps = ({
229
235
 
230
236
  const executeSignature = async ({
231
237
  signatureStep,
232
- }: { signatureStep: Step }) => {
238
+ }: {
239
+ signatureStep: Step;
240
+ }) => {
233
241
  if (!wallet) return;
234
242
 
235
243
  const signature = await wallet.handleSignMessageStep(
@@ -5,7 +5,7 @@ import type { BaseModalState, ModalCallbacks } from '../_internal/types';
5
5
 
6
6
  export type OpenSellModalArgs = {
7
7
  collectionAddress: Hex;
8
- chainId: string;
8
+ chainId: number;
9
9
  tokenId: string;
10
10
  order: Order;
11
11
  callbacks?: ModalCallbacks;
@@ -15,6 +15,7 @@ type SellModalState = BaseModalState & {
15
15
  tokenId: string;
16
16
  order?: Order;
17
17
  steps: TransactionSteps;
18
+ sellIsBeingProcessed: boolean;
18
19
  };
19
20
 
20
21
  type Actions = {
@@ -25,11 +26,11 @@ type Actions = {
25
26
  const initialState: SellModalState & Actions = {
26
27
  isOpen: false,
27
28
  collectionAddress: '' as Hex,
28
- chainId: '',
29
+ chainId: 0,
29
30
  tokenId: '',
30
31
  order: undefined,
31
32
  callbacks: undefined,
32
-
33
+ sellIsBeingProcessed: false,
33
34
  open: (args) => {
34
35
  sellModal$.collectionAddress.set(args.collectionAddress);
35
36
  sellModal$.chainId.set(args.chainId);
@@ -42,6 +43,7 @@ const initialState: SellModalState & Actions = {
42
43
  close: () => {
43
44
  sellModal$.isOpen.set(false);
44
45
  sellModal$.callbacks.set(undefined);
46
+ sellModal$.sellIsBeingProcessed.set(false);
45
47
  },
46
48
  steps: {
47
49
  approval: {
@@ -4,20 +4,26 @@ import type { ShowTransferModalArgs } from '.';
4
4
  import type { CollectionType } from '../../../_internal';
5
5
  import type { ModalCallbacks } from '../_internal/types';
6
6
 
7
+ export type TransferModalView =
8
+ | 'enterReceiverAddress'
9
+ | 'followWalletInstructions'
10
+ | undefined;
11
+
7
12
  export interface TransferModalState {
8
13
  isOpen: boolean;
9
14
  open: (args: ShowTransferModalArgs) => void;
10
15
  close: () => void;
11
16
  state: {
12
- chainId: string;
17
+ chainId: number;
13
18
  collectionAddress: Hex;
14
19
  collectionType?: CollectionType | undefined;
15
20
  collectibleId: string;
16
21
  quantity: string;
17
22
  receiverAddress: string;
18
23
  callbacks?: ModalCallbacks;
24
+ transferIsBeingProcessed: boolean;
19
25
  };
20
- view: 'enterReceiverAddress' | 'followWalletInstructions' | undefined;
26
+ view: TransferModalView;
21
27
  hash: Hex | undefined;
22
28
  }
23
29
 
@@ -40,18 +46,24 @@ export const initialState: TransferModalState = {
40
46
  },
41
47
  close: () => {
42
48
  transferModal$.isOpen.set(false);
49
+
50
+ // TODO: this doesn't work as expected
43
51
  transferModal$.state.set({
44
52
  ...initialState.state,
45
53
  });
54
+
55
+ transferModal$.state.receiverAddress.set('');
56
+ transferModal$.state.transferIsBeingProcessed.set(false);
46
57
  transferModal$.view.set('enterReceiverAddress');
47
58
  transferModal$.hash.set(undefined);
48
59
  },
49
60
  state: {
50
61
  receiverAddress: '',
51
62
  collectionAddress: '0x',
52
- chainId: '',
63
+ chainId: 0,
53
64
  collectibleId: '',
54
65
  quantity: '1',
66
+ transferIsBeingProcessed: false,
55
67
  },
56
68
  view: 'enterReceiverAddress',
57
69
  hash: undefined,
@@ -0,0 +1,58 @@
1
+ import { cn } from '@0xsequence/design-system';
2
+ import { Text } from '@0xsequence/design-system';
3
+ import { observable } from '@legendapp/state';
4
+ import { observer } from '@legendapp/state/react';
5
+ import QuantityInput from '../../../../_internal/components/quantityInput';
6
+ import { transferModal$ } from '../../../_store';
7
+
8
+ const TokenQuantityInput = observer(
9
+ ({
10
+ balanceAmount,
11
+ collection,
12
+ isProcessingWithWaaS,
13
+ }: {
14
+ balanceAmount?: bigint;
15
+ collection?: { decimals?: number };
16
+ isProcessingWithWaaS: boolean;
17
+ }) => {
18
+ const $quantity = transferModal$.state.quantity;
19
+ const $invalidQuantity = observable(false);
20
+
21
+ let insufficientBalance = true;
22
+ if (balanceAmount !== undefined && $quantity.get()) {
23
+ try {
24
+ const quantityBigInt = BigInt($quantity.get());
25
+ insufficientBalance = quantityBigInt > balanceAmount;
26
+ } catch (e) {
27
+ insufficientBalance = true;
28
+ }
29
+ }
30
+
31
+ return (
32
+ <div
33
+ className={cn(
34
+ 'flex flex-col gap-3',
35
+ isProcessingWithWaaS && 'pointer-events-none opacity-50',
36
+ )}
37
+ >
38
+ <QuantityInput
39
+ $quantity={$quantity}
40
+ $invalidQuantity={$invalidQuantity}
41
+ decimals={collection?.decimals || 0}
42
+ maxQuantity={balanceAmount ? String(balanceAmount) : '0'}
43
+ className="[&>label>div>div]:h-13 [&>label>div>div]:rounded-xl [&>label>div>span]:text-sm [&>label>div>span]:text-text-80 [&>label]:gap-1"
44
+ />
45
+
46
+ <Text
47
+ className="font-body text-xs"
48
+ color={insufficientBalance ? 'negative' : 'text50'}
49
+ fontWeight="medium"
50
+ >
51
+ {`You have ${balanceAmount?.toString() || '0'} of this item`}
52
+ </Text>
53
+ </div>
54
+ );
55
+ },
56
+ );
57
+
58
+ export default TokenQuantityInput;