@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
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+
3
+ import { getNetwork } from '@0xsequence/connect';
4
+ import { Button, Spinner } from '@0xsequence/design-system';
5
+ import { NetworkType } from '@0xsequence/network';
6
+ import { observer } from '@legendapp/state/react';
7
+ import { useWallet } from '../../../../../../_internal/wallet/useWallet';
8
+ import { transferModal$ } from '../../../_store';
9
+
10
+ const TransferButton = observer(
11
+ ({
12
+ onClick,
13
+ isDisabled,
14
+ chainId,
15
+ }: {
16
+ onClick: () => Promise<void>;
17
+ isDisabled: boolean | undefined;
18
+ chainId: number;
19
+ }) => {
20
+ const { wallet } = useWallet();
21
+ const network = getNetwork(chainId);
22
+ const isWaaS = wallet?.isWaaS;
23
+ const isTestnet = network.type === NetworkType.TESTNET;
24
+ const isProcessing = transferModal$.state.transferIsBeingProcessed.get();
25
+ const label = isProcessing ? (
26
+ isWaaS && !isTestnet ? (
27
+ <div className="flex items-center justify-center gap-2">
28
+ <Spinner size="sm" className="text-white" />
29
+ <span>Loading fee options</span>
30
+ </div>
31
+ ) : (
32
+ <div className="flex items-center justify-center gap-2">
33
+ <Spinner size="sm" className="text-white" />
34
+ <span>Transferring</span>
35
+ </div>
36
+ )
37
+ ) : (
38
+ 'Transfer'
39
+ );
40
+
41
+ return (
42
+ <Button
43
+ className="flex justify-self-end px-10"
44
+ onClick={onClick}
45
+ disabled={!!isDisabled}
46
+ title="Transfer"
47
+ label={label}
48
+ variant="primary"
49
+ shape="square"
50
+ size="sm"
51
+ />
52
+ );
53
+ },
54
+ );
55
+
56
+ export default TransferButton;
@@ -0,0 +1,50 @@
1
+ 'use client';
2
+
3
+ import { TextInput } from '@0xsequence/design-system';
4
+ import { observer } from '@legendapp/state/react';
5
+ import { isAddress } from 'viem';
6
+ import { useAccount } from 'wagmi';
7
+ import { transferModal$ } from '../../../_store';
8
+
9
+ const MAX_WALLET_ADDRESS_LENGTH = 42;
10
+
11
+ const WalletAddressInput = observer(() => {
12
+ const { address: connectedAddress } = useAccount();
13
+ const receiverAddress = transferModal$.state.receiverAddress.get();
14
+ const isWalletAddressValid = isAddress(receiverAddress);
15
+ const isProcessing = transferModal$.state.transferIsBeingProcessed.get();
16
+
17
+ const isSelfTransfer =
18
+ isWalletAddressValid &&
19
+ connectedAddress &&
20
+ receiverAddress.toLowerCase() === connectedAddress.toLowerCase();
21
+
22
+ const handleChangeWalletAddress = (
23
+ event: React.ChangeEvent<HTMLInputElement>,
24
+ ) => {
25
+ transferModal$.state.receiverAddress.set(event.target.value);
26
+ };
27
+
28
+ return (
29
+ <div className="[&>label>div>span]:text-sm [&>label>div>span]:text-text-80 [&>label]:gap-1">
30
+ <TextInput
31
+ label="Wallet address"
32
+ labelLocation="top"
33
+ autoFocus
34
+ value={receiverAddress}
35
+ maxLength={MAX_WALLET_ADDRESS_LENGTH}
36
+ onChange={handleChangeWalletAddress}
37
+ name="walletAddress"
38
+ placeholder="Enter wallet address"
39
+ disabled={isProcessing}
40
+ />
41
+ {isSelfTransfer && (
42
+ <div className="mt-1 text-negative text-sm">
43
+ You cannot transfer to your own address
44
+ </div>
45
+ )}
46
+ </div>
47
+ );
48
+ });
49
+
50
+ export default WalletAddressInput;
@@ -1,114 +1,142 @@
1
1
  'use client';
2
2
 
3
- import { Button, Text, TextInput } from '@0xsequence/design-system';
4
- import { observable } from '@legendapp/state';
3
+ import { Text } from '@0xsequence/design-system';
4
+ import { observer } from '@legendapp/state/react';
5
5
  import { isAddress } from 'viem';
6
6
  import { useAccount } from 'wagmi';
7
7
  import { useCollection, useListBalances } from '../../../../..';
8
+ import type { FeeOption } from '../../../../../../types/waas-types';
9
+ import { compareAddress } from '../../../../../../utils';
8
10
  import { type CollectionType, ContractType } from '../../../../../_internal';
9
11
  import AlertMessage from '../../../_internal/components/alertMessage';
10
- import QuantityInput from '../../../_internal/components/quantityInput';
12
+ import { selectWaasFeeOptions$ } from '../../../_internal/components/selectWaasFeeOptions/store';
13
+ import { useSelectWaasFeeOptions } from '../../../_internal/hooks/useSelectWaasFeeOptions';
11
14
  import { transferModal$ } from '../../_store';
12
15
  import getMessage from '../../messages';
16
+ import TokenQuantityInput from './_components/TokenQuantityInput';
17
+ import TransferButton from './_components/TransferButton';
18
+ import WalletAddressInput from './_components/WalletAddressInput';
13
19
  import useHandleTransfer from './useHandleTransfer';
14
20
 
15
- const EnterWalletAddressView = () => {
16
- const { address } = useAccount();
21
+ const EnterWalletAddressView = observer(() => {
22
+ const { address: connectedAddress } = useAccount();
17
23
  const { collectionAddress, collectibleId, chainId, collectionType } =
18
24
  transferModal$.state.get();
19
25
  const $quantity = transferModal$.state.quantity;
20
- const $invalidQuantity = observable(false);
21
- const isWalletAddressValid = isAddress(
22
- transferModal$.state.receiverAddress.get(),
23
- );
26
+ const receiverAddress = transferModal$.state.receiverAddress.get();
27
+ const isWalletAddressValid = isAddress(receiverAddress);
28
+ const {
29
+ isWaaS,
30
+ isProcessingWithWaaS,
31
+ shouldHideActionButton: shouldHideTransferButton,
32
+ } = useSelectWaasFeeOptions({
33
+ chainId,
34
+ isProcessing: transferModal$.state.transferIsBeingProcessed.get(),
35
+ feeOptionsVisible: selectWaasFeeOptions$.isVisible.get(),
36
+ selectedFeeOption:
37
+ selectWaasFeeOptions$.selectedFeeOption.get() as FeeOption,
38
+ });
39
+
40
+ const isSelfTransfer =
41
+ isWalletAddressValid &&
42
+ connectedAddress &&
43
+ compareAddress(receiverAddress, connectedAddress);
44
+
24
45
  const { data: tokenBalance } = useListBalances({
25
- chainId: Number(chainId),
46
+ chainId,
26
47
  contractAddress: collectionAddress,
27
48
  tokenId: collectibleId,
28
- accountAddress: address,
29
- query: { enabled: !!address },
49
+ accountAddress: connectedAddress,
50
+ query: { enabled: !!connectedAddress },
30
51
  });
52
+
31
53
  const balanceAmount = tokenBalance?.pages[0].balances[0].balance;
32
- const insufficientBalance: boolean = balanceAmount
33
- ? $quantity.get() > balanceAmount
34
- : true;
54
+
55
+ let insufficientBalance = true;
56
+ if (balanceAmount !== undefined && $quantity.get()) {
57
+ try {
58
+ const quantityBigInt = BigInt($quantity.get());
59
+ insufficientBalance = quantityBigInt > BigInt(balanceAmount);
60
+ } catch (e) {
61
+ insufficientBalance = true;
62
+ }
63
+ }
64
+
35
65
  const { data: collection } = useCollection({
36
66
  collectionAddress,
37
67
  chainId,
38
68
  });
69
+
39
70
  transferModal$.state.collectionType.set(
40
71
  collection?.type as CollectionType | undefined,
41
72
  );
73
+
42
74
  const { transfer } = useHandleTransfer();
43
75
 
44
- function handleChangeWalletAddress(
45
- event: React.ChangeEvent<HTMLInputElement>,
46
- ) {
47
- transferModal$.state.receiverAddress.set(event.target.value);
48
- }
76
+ const onTransferClick = async () => {
77
+ transferModal$.state.transferIsBeingProcessed.set(true);
49
78
 
50
- function handleChangeView() {
51
- transfer();
52
- transferModal$.view.set('followWalletInstructions');
53
- }
79
+ try {
80
+ if (!isWaaS) {
81
+ transferModal$.view.set('followWalletInstructions');
82
+ } else {
83
+ selectWaasFeeOptions$.isVisible.set(true);
84
+ }
85
+
86
+ await transfer();
87
+ } catch (error) {
88
+ console.error('Transfer failed:', error);
89
+ } finally {
90
+ if (transferModal$.view.get() === 'enterReceiverAddress') {
91
+ transferModal$.state.transferIsBeingProcessed.set(false);
92
+ }
93
+ }
94
+ };
95
+
96
+ const isErc1155 = collectionType === ContractType.ERC1155;
97
+ const showQuantityInput = isErc1155 && !!balanceAmount;
98
+ const isProcessing = !!transferModal$.state.transferIsBeingProcessed.get();
99
+
100
+ const isTransferDisabled =
101
+ isProcessing ||
102
+ !isWalletAddressValid ||
103
+ insufficientBalance ||
104
+ !$quantity.get() ||
105
+ Number($quantity.get()) === 0 ||
106
+ isSelfTransfer;
54
107
 
55
108
  return (
56
109
  <div className="grid grow gap-6">
57
110
  <Text className="font-body text-xl" color="white" fontWeight="bold">
58
111
  Transfer your item
59
112
  </Text>
113
+
60
114
  <div className="flex flex-col gap-3">
61
115
  <AlertMessage
62
116
  message={getMessage('enterReceiverAddress')}
63
117
  type="warning"
64
118
  />
65
119
 
66
- <div className="[&>label>div>span]:text-sm [&>label>div>span]:text-text-80 [&>label]:gap-1">
67
- <TextInput
68
- label="Wallet address"
69
- labelLocation="top"
70
- autoFocus
71
- value={transferModal$.state.receiverAddress.get()}
72
- onChange={handleChangeWalletAddress}
73
- name="walletAddress"
74
- placeholder="Enter wallet address"
120
+ <WalletAddressInput />
121
+
122
+ {showQuantityInput && (
123
+ <TokenQuantityInput
124
+ balanceAmount={balanceAmount ? BigInt(balanceAmount) : undefined}
125
+ collection={collection}
126
+ isProcessingWithWaaS={isProcessingWithWaaS ?? false}
75
127
  />
76
- </div>
77
-
78
- {collectionType === ContractType.ERC1155 && balanceAmount && (
79
- <>
80
- <QuantityInput
81
- $quantity={$quantity}
82
- $invalidQuantity={$invalidQuantity}
83
- decimals={collection?.decimals || 0}
84
- maxQuantity={balanceAmount}
85
- 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"
86
- />
87
-
88
- <Text
89
- className="font-body text-xs"
90
- color={insufficientBalance ? 'negative' : 'text50'}
91
- fontWeight="medium"
92
- >
93
- {`You have ${balanceAmount} of this item`}
94
- </Text>
95
- </>
96
128
  )}
97
129
  </div>
98
- <Button
99
- className="flex justify-self-end px-10"
100
- onClick={handleChangeView}
101
- disabled={
102
- !isWalletAddressValid || insufficientBalance || !$quantity.get()
103
- }
104
- title="Transfer"
105
- label="Transfer"
106
- variant="primary"
107
- shape="square"
108
- size="sm"
109
- />
130
+
131
+ {!shouldHideTransferButton && (
132
+ <TransferButton
133
+ onClick={onTransferClick}
134
+ isDisabled={isTransferDisabled}
135
+ chainId={chainId}
136
+ />
137
+ )}
110
138
  </div>
111
139
  );
112
- };
140
+ });
113
141
 
114
142
  export default EnterWalletAddressView;
@@ -1,8 +1,10 @@
1
+ import { useWaasFeeOptions } from '@0xsequence/connect';
1
2
  import type { Hex } from 'viem';
2
3
  import { ContractType } from '../../../../../../types';
3
4
  import { InvalidContractTypeError } from '../../../../../../utils/_internal/error/transaction';
4
5
  import { balanceQueries, collectableKeys } from '../../../../../_internal';
5
6
  import { TransactionType } from '../../../../../_internal/types';
7
+ import { useWallet } from '../../../../../_internal/wallet/useWallet';
6
8
  import { useTransferTokens } from '../../../../../hooks';
7
9
  import { useTransactionStatusModal } from '../../../_internal/components/transactionStatusModal';
8
10
  import { transferModal$ } from '../../_store';
@@ -17,32 +19,36 @@ const useHandleTransfer = () => {
17
19
  collectionType,
18
20
  callbacks,
19
21
  } = transferModal$.state.get();
22
+
20
23
  const { transferTokensAsync } = useTransferTokens();
21
24
  const { show: showTransactionStatusModal } = useTransactionStatusModal();
25
+ const { wallet } = useWallet();
26
+ const [pendingFeeOptionConfirmation] = useWaasFeeOptions();
27
+
28
+ const getHash = async (): Promise<Hex> => {
29
+ const baseParams = {
30
+ receiverAddress: receiverAddress as Hex,
31
+ collectionAddress,
32
+ tokenId: collectibleId,
33
+ chainId,
34
+ };
22
35
 
23
- const getHash = async () => {
24
36
  if (collectionType === ContractType.ERC721) {
25
37
  return await transferTokensAsync({
26
- receiverAddress: receiverAddress as Hex,
27
- collectionAddress,
28
- tokenId: collectibleId,
29
- chainId,
38
+ ...baseParams,
30
39
  contractType: ContractType.ERC721,
31
40
  });
32
41
  }
33
42
 
34
43
  // For ERC1155
35
44
  return await transferTokensAsync({
36
- receiverAddress: receiverAddress as Hex,
37
- collectionAddress,
38
- tokenId: collectibleId,
39
- chainId,
45
+ ...baseParams,
40
46
  contractType: ContractType.ERC1155,
41
47
  quantity: String(quantity),
42
48
  });
43
49
  };
44
50
 
45
- async function transfer() {
51
+ const transfer = async (): Promise<void> => {
46
52
  if (
47
53
  collectionType !== ContractType.ERC721 &&
48
54
  collectionType !== ContractType.ERC1155
@@ -50,13 +56,16 @@ const useHandleTransfer = () => {
50
56
  throw new InvalidContractTypeError(collectionType);
51
57
  }
52
58
 
59
+ if (wallet?.isWaaS && pendingFeeOptionConfirmation) {
60
+ return;
61
+ }
62
+
53
63
  try {
54
64
  const hash = await getHash();
55
-
56
65
  transferModal$.close();
57
66
 
58
67
  showTransactionStatusModal({
59
- hash: hash,
68
+ hash,
60
69
  collectionAddress,
61
70
  chainId,
62
71
  collectibleId,
@@ -69,10 +78,9 @@ const useHandleTransfer = () => {
69
78
  });
70
79
  } catch (error) {
71
80
  transferModal$.view.set('enterReceiverAddress');
72
-
73
81
  callbacks?.onError?.(error as Error);
74
82
  }
75
- }
83
+ };
76
84
 
77
85
  return { transfer };
78
86
  };
@@ -2,99 +2,133 @@
2
2
 
3
3
  import { Modal } from '@0xsequence/design-system';
4
4
  import { observer } from '@legendapp/state/react';
5
- import type { Hex } from 'viem';
6
- import { useAccount } from 'wagmi';
5
+ import type { Address } from 'viem';
6
+ import { useAccount, useSwitchChain } from 'wagmi';
7
+ import type { FeeOption } from '../../../../types/waas-types';
8
+ import { useWallet } from '../../../_internal/wallet/useWallet';
7
9
  import { MODAL_OVERLAY_PROPS } from '../_internal/components/consts';
10
+ import SelectWaasFeeOptions from '../_internal/components/selectWaasFeeOptions';
11
+ import { selectWaasFeeOptions$ } from '../_internal/components/selectWaasFeeOptions/store';
8
12
  import { useSwitchChainModal } from '../_internal/components/switchChainModal';
13
+ import { useSelectWaasFeeOptions } from '../_internal/hooks/useSelectWaasFeeOptions';
9
14
  import type { ModalCallbacks } from '../_internal/types';
10
15
  import { transferModal$ } from './_store';
11
16
  import EnterWalletAddressView from './_views/enterWalletAddress';
12
17
  import FollowWalletInstructionsView from './_views/followWalletInstructions';
13
18
 
14
19
  export type ShowTransferModalArgs = {
15
- collectionAddress: Hex;
20
+ collectionAddress: Address;
16
21
  collectibleId: string;
17
- chainId: string;
22
+ chainId: number;
18
23
  callbacks?: ModalCallbacks;
19
24
  };
20
25
 
21
26
  export const useTransferModal = () => {
22
27
  const { chainId: accountChainId } = useAccount();
23
28
  const { show: showSwitchNetworkModal } = useSwitchChainModal();
29
+ const { wallet } = useWallet();
30
+ const { switchChain } = useSwitchChain();
24
31
 
25
32
  const openModal = (args: ShowTransferModalArgs) => {
26
33
  transferModal$.open(args);
27
34
  };
28
35
 
29
36
  const handleShowModal = (args: ShowTransferModalArgs) => {
30
- const isSameChain = accountChainId === Number(args.chainId);
37
+ const targetChainId = Number(args.chainId);
38
+ const isSameChain = accountChainId === targetChainId;
31
39
 
32
40
  if (!isSameChain) {
33
- showSwitchNetworkModal({
34
- chainIdToSwitchTo: Number(args.chainId),
35
- onSuccess: () => openModal(args),
36
- });
41
+ if (wallet?.isWaaS) {
42
+ switchChain({ chainId: targetChainId });
43
+
44
+ openModal(args);
45
+ } else {
46
+ showSwitchNetworkModal({
47
+ chainIdToSwitchTo: targetChainId,
48
+ onSuccess: () => openModal(args),
49
+ });
50
+ }
37
51
  return;
38
52
  }
39
53
 
40
54
  openModal(args);
41
55
  };
42
56
 
57
+ const updateCallbacks = (callbacks: ModalCallbacks) => {
58
+ transferModal$.state.set({
59
+ ...transferModal$.state.get(),
60
+ callbacks,
61
+ });
62
+ };
63
+
43
64
  return {
44
65
  show: handleShowModal,
45
- close: () => transferModal$.close(),
46
- onError: (callbacks: ModalCallbacks) => {
47
- transferModal$.state.set({
48
- ...transferModal$.state.get(),
49
- callbacks,
50
- });
51
- },
52
- onSuccess: (callbacks: ModalCallbacks) => {
53
- transferModal$.state.set({
54
- ...transferModal$.state.get(),
55
- callbacks,
56
- });
57
- },
66
+ close: transferModal$.close,
67
+ onError: updateCallbacks,
68
+ onSuccess: updateCallbacks,
58
69
  };
59
70
  };
60
71
 
72
+ const TransactionModalView = observer(() => {
73
+ const { view } = transferModal$.get();
74
+
75
+ switch (view) {
76
+ case 'enterReceiverAddress':
77
+ return <EnterWalletAddressView />;
78
+ case 'followWalletInstructions':
79
+ return <FollowWalletInstructionsView />;
80
+ default:
81
+ return null;
82
+ }
83
+ });
84
+
61
85
  const TransferModal = observer(() => {
62
86
  const isOpen = transferModal$.isOpen.get();
87
+ const chainId = transferModal$.state.chainId.get();
88
+ const isTransferBeingProcessed =
89
+ transferModal$.state.transferIsBeingProcessed.get();
90
+ const { waasFeeOptionsShown } = useSelectWaasFeeOptions({
91
+ chainId: chainId,
92
+ isProcessing: isTransferBeingProcessed,
93
+ feeOptionsVisible: selectWaasFeeOptions$.isVisible.get(),
94
+ selectedFeeOption:
95
+ selectWaasFeeOptions$.selectedFeeOption.get() as FeeOption,
96
+ });
63
97
 
64
98
  if (!isOpen) return null;
65
99
 
66
100
  return (
67
101
  <Modal
68
102
  isDismissible={true}
69
- onClose={transferModal$.close}
103
+ onClose={() => {
104
+ transferModal$.close();
105
+ selectWaasFeeOptions$.hide();
106
+ }}
70
107
  size="sm"
71
108
  overlayProps={MODAL_OVERLAY_PROPS}
72
109
  contentProps={{
73
110
  style: {
74
111
  height: 'auto',
112
+ overflow: 'auto',
75
113
  },
76
114
  }}
77
115
  >
78
116
  <div className="flex w-full flex-col p-7">
79
117
  <TransactionModalView />
80
118
  </div>
119
+
120
+ {waasFeeOptionsShown && (
121
+ <SelectWaasFeeOptions
122
+ chainId={Number(chainId)}
123
+ onCancel={() => {
124
+ transferModal$.state.transferIsBeingProcessed.set(false);
125
+ }}
126
+ titleOnConfirm="Processing transfer..."
127
+ className="p-7 pt-0"
128
+ />
129
+ )}
81
130
  </Modal>
82
131
  );
83
132
  });
84
133
 
85
- const TransactionModalView = observer(() => {
86
- const { view } = transferModal$.get();
87
-
88
- switch (view) {
89
- case 'enterReceiverAddress':
90
- return <EnterWalletAddressView />;
91
-
92
- case 'followWalletInstructions':
93
- return <FollowWalletInstructionsView />;
94
-
95
- default:
96
- return null;
97
- }
98
- });
99
-
100
134
  export { TransferModal };