From 838adf9e1e83c03e95e13bb3ed5e4f32f51a6173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Mon, 8 Apr 2024 18:10:40 +0200 Subject: [PATCH 001/103] WalletConnect EVM support --- .../transaction/ReviewTransactionForm.tsx | 15 +- .../ReviewTransactionXCallForm.tsx | 4 +- .../web3-connect/Web3Connect.utils.ts | 37 ++- .../modal/Web3ConnectWalletLoader.tsx | 59 ++++ .../providers/Web3ConnectProviderButton.tsx | 8 +- .../providers/Web3ConnectProviderPending.tsx | 58 +--- .../providers/Web3ConnectWCSelector.tsx | 85 ++++++ .../EthereumSigner.ts} | 35 ++- .../PolkadotSigner.ts} | 2 +- .../wallets/{MetaMask => }/MetaMask.ts | 6 +- .../web3-connect/wallets/MetaMask/index.ts | 2 - .../web3-connect/wallets/TalismanEvm.ts | 2 +- .../web3-connect/wallets/WalletConnect.ts | 265 ++++++++++++++++++ .../wallets/WalletConnect/WalletConnect.ts | 145 ---------- .../wallets/WalletConnect/index.ts | 1 - src/sections/web3-connect/wallets/index.ts | 16 +- src/utils/metamask.ts | 3 +- 17 files changed, 509 insertions(+), 234 deletions(-) create mode 100644 src/sections/web3-connect/modal/Web3ConnectWalletLoader.tsx create mode 100644 src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx rename src/sections/web3-connect/{wallets/MetaMask/MetaMaskSigner.ts => signer/EthereumSigner.ts} (66%) rename src/sections/web3-connect/{wallets/WalletConnect/WalletConnectSigner.ts => signer/PolkadotSigner.ts} (97%) rename src/sections/web3-connect/wallets/{MetaMask => }/MetaMask.ts (95%) delete mode 100644 src/sections/web3-connect/wallets/MetaMask/index.ts create mode 100644 src/sections/web3-connect/wallets/WalletConnect.ts delete mode 100644 src/sections/web3-connect/wallets/WalletConnect/WalletConnect.ts delete mode 100644 src/sections/web3-connect/wallets/WalletConnect/index.ts diff --git a/src/sections/transaction/ReviewTransactionForm.tsx b/src/sections/transaction/ReviewTransactionForm.tsx index 8cfbc7787..ba156271d 100644 --- a/src/sections/transaction/ReviewTransactionForm.tsx +++ b/src/sections/transaction/ReviewTransactionForm.tsx @@ -1,5 +1,5 @@ import { TransactionResponse } from "@ethersproject/providers" -import { FC, useState } from "react" +import { FC, useEffect, useState } from "react" import { SubmittableExtrinsic } from "@polkadot/api/types" import { useMutation } from "@tanstack/react-query" import { Button } from "components/Button/Button" @@ -7,7 +7,6 @@ import { ModalScrollableContent } from "components/Modal/Modal" import { Text } from "components/Typography/Text/Text" import { useTranslation } from "react-i18next" import { useAccount, useWallet } from "sections/web3-connect/Web3Connect.utils" -import { MetaMaskSigner } from "sections/web3-connect/wallets/MetaMask/MetaMaskSigner" import { Transaction, useStore } from "state/store" import { theme } from "theme" import { ReviewTransactionData } from "./ReviewTransactionData" @@ -26,6 +25,9 @@ import { isEvmAccount, } from "utils/evm" import { isSetCurrencyExtrinsic } from "sections/transaction/ReviewTransaction.utils" +import { EthereumSigner } from "sections/web3-connect/signer/EthereumSigner" +import { WalletConnect } from "sections/web3-connect/wallets/WalletConnect" +import { POLKADOT_APP_NAME } from "utils/api" type TxProps = Omit & { tx: SubmittableExtrinsic<"promise"> @@ -92,9 +94,16 @@ export const ReviewTransactionForm: FC = (props) => { if (!address) throw new Error("Missing active account") if (!wallet) throw new Error("Missing wallet") + + if (wallet instanceof WalletConnect && !wallet._session) { + const isEvm = isEvmAccount(address) + await wallet.setNamespace(isEvm ? "eip155" : "polkadot") + await wallet.enable(POLKADOT_APP_NAME) + } + if (!wallet.signer) throw new Error("Missing signer") - if (wallet?.signer instanceof MetaMaskSigner) { + if (wallet?.signer instanceof EthereumSigner) { const evmTx = await wallet.signer.sendDispatch(tx.method.toHex()) return props.onEvmSigned({ evmTx, tx }) } diff --git a/src/sections/transaction/ReviewTransactionXCallForm.tsx b/src/sections/transaction/ReviewTransactionXCallForm.tsx index 75c2055fa..50461decc 100644 --- a/src/sections/transaction/ReviewTransactionXCallForm.tsx +++ b/src/sections/transaction/ReviewTransactionXCallForm.tsx @@ -12,7 +12,7 @@ import { useEvmAccount, useWallet, } from "sections/web3-connect/Web3Connect.utils" -import { MetaMaskSigner } from "sections/web3-connect/wallets/MetaMask/MetaMaskSigner" +import { EthereumSigner } from "sections/web3-connect/signer/EthereumSigner" import { Transaction } from "state/store" import { theme } from "theme" @@ -45,7 +45,7 @@ export const ReviewTransactionXCallForm: FC = ({ if (!wallet.signer) throw new Error("Missing signer") if (!isEvmXCall(xcall)) throw new Error("Missing xcall") - if (wallet?.signer instanceof MetaMaskSigner) { + if (wallet?.signer instanceof EthereumSigner) { const { srcChain } = xcallMeta const evmTx = await wallet.signer.sendTransaction({ diff --git a/src/sections/web3-connect/Web3Connect.utils.ts b/src/sections/web3-connect/Web3Connect.utils.ts index ea3cfeccc..ccee9a282 100644 --- a/src/sections/web3-connect/Web3Connect.utils.ts +++ b/src/sections/web3-connect/Web3Connect.utils.ts @@ -9,7 +9,10 @@ import { useShallow } from "hooks/useShallow" import { useEffect, useRef } from "react" import { usePrevious } from "react-use" -import { WalletConnect } from "sections/web3-connect/wallets/WalletConnect" +import { + NamespaceType, + WalletConnect, +} from "sections/web3-connect/wallets/WalletConnect" import { POLKADOT_APP_NAME } from "utils/api" import { H160, getEvmAddress, isEvmAddress } from "utils/evm" import { safeConvertAddressSS58 } from "utils/formatting" @@ -21,12 +24,13 @@ import { } from "./store/useWeb3ConnectStore" import { WalletProviderType, getSupportedWallets } from "./wallets" import { ExternalWallet } from "./wallets/ExternalWallet" -import { MetaMask } from "./wallets/MetaMask/MetaMask" +import { MetaMask } from "./wallets/MetaMask" import { isMetaMask, requestNetworkSwitch } from "utils/metamask" import { genesisHashToChain } from "utils/helpers" import { WalletAccount } from "sections/web3-connect/types" import { EVM_PROVIDERS } from "sections/web3-connect/constants/providers" import { useAddressStore } from "components/AddressBook/AddressBook.utils" +import { EthereumSigner } from "sections/web3-connect/signer/EthereumSigner" export type { WalletProvider } from "./wallets" export { WalletProviderType, getSupportedWallets } @@ -190,8 +194,15 @@ export const useWeb3ConnectEagerEnable = () => { function cleanUp() { const metamask = prevWallet instanceof MetaMask ? prevWallet : null + const walletConnect = + prevWallet instanceof WalletConnect ? prevWallet : null const external = prevWallet instanceof ExternalWallet ? prevWallet : null + if (walletConnect) { + // disconnect from WalletConnect + walletConnect.disconnect() + } + if (metamask) { // unsub from metamask events on disconnect metamask.unsubscribe() @@ -208,13 +219,27 @@ export const useWeb3ConnectEagerEnable = () => { export const useEnableWallet = ( provider: WalletProviderType | null, - options?: MutationObserverOptions, + options?: MutationObserverOptions< + WalletAccount[] | undefined, + unknown, + NamespaceType | void, + unknown + >, ) => { const { wallet } = getWalletProviderByType(provider) const { add: addToAddressBook } = useAddressStore() const meta = useWeb3ConnectStore(useShallow((state) => state.meta)) - const { mutate: enable, ...mutation } = useMutation( - async () => { + const { mutate: enable, ...mutation } = useMutation< + WalletAccount[] | undefined, + unknown, + NamespaceType | void, + unknown + >( + async (namespace) => { + if (wallet instanceof WalletConnect && namespace) { + wallet.setNamespace(namespace) + } + await wallet?.enable(POLKADOT_APP_NAME) if (wallet instanceof MetaMask) { @@ -315,7 +340,7 @@ export function getWalletProviderByType(type?: WalletProviderType | null) { function getProviderQueryKey(type: WalletProviderType | null) { const { wallet } = getWalletProviderByType(type) - if (wallet instanceof MetaMask) { + if (wallet?.signer instanceof EthereumSigner) { return [type, wallet.signer?.address].join("-") } diff --git a/src/sections/web3-connect/modal/Web3ConnectWalletLoader.tsx b/src/sections/web3-connect/modal/Web3ConnectWalletLoader.tsx new file mode 100644 index 000000000..efbe29b6a --- /dev/null +++ b/src/sections/web3-connect/modal/Web3ConnectWalletLoader.tsx @@ -0,0 +1,59 @@ +import { css } from "@emotion/react" +import { Text } from "components/Typography/Text/Text" +import { useTranslation } from "react-i18next" +import { + WalletProviderType, + getWalletProviderByType, +} from "sections/web3-connect/Web3Connect.utils" +import { FC } from "react" +import { Spinner } from "components/Spinner/Spinner" + +type Props = { provider: WalletProviderType } + +export const Web3ConnectWalletLoader: FC = ({ provider }) => { + const { t } = useTranslation() + const { wallet } = getWalletProviderByType(provider) + return ( +
+
* { + grid-column: 1; + grid-row: 1; + } + `} + > + + {wallet?.logo.alt} +
+ + {t("walletConnect.pending.title")} + +
+ + {t("walletConnect.pending.description", { + name: wallet?.title, + })} + +
+
+ ) +} diff --git a/src/sections/web3-connect/providers/Web3ConnectProviderButton.tsx b/src/sections/web3-connect/providers/Web3ConnectProviderButton.tsx index 926638904..bfea257cf 100644 --- a/src/sections/web3-connect/providers/Web3ConnectProviderButton.tsx +++ b/src/sections/web3-connect/providers/Web3ConnectProviderButton.tsx @@ -5,6 +5,7 @@ import { FC } from "react" import { useTranslation } from "react-i18next" import { WalletProvider, + WalletProviderType, useEnableWallet, } from "sections/web3-connect/Web3Connect.utils" import { SProviderButton } from "./Web3ConnectProviders.styled" @@ -34,7 +35,12 @@ export const Web3ConnectProviderButton: FC = ({ type, wallet }) => { }) function onClick() { - installed ? enable() : openInstallUrl(installUrl) + if (type === WalletProviderType.WalletConnect) { + // defer WalletConnect enabling until the user clicks chooses a chain to connect to + setStatus(type, WalletProviderStatus.Pending) + } else { + installed ? enable() : openInstallUrl(installUrl) + } } return ( diff --git a/src/sections/web3-connect/providers/Web3ConnectProviderPending.tsx b/src/sections/web3-connect/providers/Web3ConnectProviderPending.tsx index 678405a12..075a68266 100644 --- a/src/sections/web3-connect/providers/Web3ConnectProviderPending.tsx +++ b/src/sections/web3-connect/providers/Web3ConnectProviderPending.tsx @@ -1,63 +1,23 @@ -import { css } from "@emotion/react" -import { Text } from "components/Typography/Text/Text" -import { useTranslation } from "react-i18next" -import { - WalletProviderType, - getWalletProviderByType, -} from "sections/web3-connect/Web3Connect.utils" import { FC } from "react" -import { Spinner } from "components/Spinner/Spinner" +import { WalletProviderType } from "sections/web3-connect/Web3Connect.utils" +import { Web3ConnectWalletLoader } from "sections/web3-connect/modal/Web3ConnectWalletLoader" +import { Web3ConnectWCSelector } from "sections/web3-connect/providers/Web3ConnectWCSelector" type Props = { provider: WalletProviderType } export const Web3ConnectProviderPending: FC = ({ provider }) => { - const { t } = useTranslation() - const { wallet } = getWalletProviderByType(provider) + const isWalletConnect = provider === WalletProviderType.WalletConnect return (
-
* { - grid-column: 1; - grid-row: 1; - } - `} - > - - {wallet?.logo.alt} -
- - {t("walletConnect.pending.title")} - -
- - {t("walletConnect.pending.description", { - name: wallet?.title, - })} - -
+ {isWalletConnect ? ( + + ) : ( + + )}
) } diff --git a/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx b/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx new file mode 100644 index 000000000..6272d1463 --- /dev/null +++ b/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx @@ -0,0 +1,85 @@ +import { Button } from "components/Button/Button" +import { useEffect } from "react" +import { + WalletProviderType, + getWalletProviderByType, + useEnableWallet, +} from "sections/web3-connect/Web3Connect.utils" +import { Web3ConnectWalletLoader } from "sections/web3-connect/modal/Web3ConnectWalletLoader" +import { + WalletProviderStatus, + useWeb3ConnectStore, +} from "sections/web3-connect/store/useWeb3ConnectStore" +import { WalletConnect } from "sections/web3-connect/wallets/WalletConnect" +import { isEvmAccount } from "utils/evm" + +export type Web3ConnectWCSelectorProps = {} + +const walletConnectType = WalletProviderType.WalletConnect + +const getWalletConnect = () => { + return getWalletProviderByType(walletConnectType).wallet as WalletConnect +} + +export const Web3ConnectWCSelector: React.FC< + Web3ConnectWCSelectorProps +> = () => { + const { setStatus, setError, provider, status, account } = + useWeb3ConnectStore() + + const { enable, isLoading } = useEnableWallet(walletConnectType, { + onSuccess: () => + setStatus(walletConnectType, WalletProviderStatus.Connected), + onError: (error) => { + setStatus(walletConnectType, WalletProviderStatus.Error) + if (error instanceof Error && error.message) { + setError(error.message) + } + }, + }) + + const wallet = getWalletConnect() + + const isConnectedToWc = + !!account?.address && + provider === walletConnectType && + status === WalletProviderStatus.Connected + + const isSessionActive = !!wallet?._session + + const shouldTriggerAutoConnect = isConnectedToWc && !isSessionActive + + useEffect(() => { + if (shouldTriggerAutoConnect) { + const isEvm = isEvmAccount(account?.address) + enable(isEvm ? "eip155" : "polkadot") + } + }, [account?.address, enable, shouldTriggerAutoConnect]) + + return ( +
+ {shouldTriggerAutoConnect || isLoading ? ( + + ) : ( +
+ + +
+ )} +
+ ) +} diff --git a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts b/src/sections/web3-connect/signer/EthereumSigner.ts similarity index 66% rename from src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts rename to src/sections/web3-connect/signer/EthereumSigner.ts index 545720b3f..70ac69b08 100644 --- a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts +++ b/src/sections/web3-connect/signer/EthereumSigner.ts @@ -4,21 +4,29 @@ import { Web3Provider, } from "@ethersproject/providers" import { evmChains } from "@galacticcouncil/xcm-sdk" +import UniversalProvider from "@walletconnect/universal-provider/dist/types/UniversalProvider" import { DISPATCH_ADDRESS } from "utils/evm" -import { MetaMaskLikeProvider, requestNetworkSwitch } from "utils/metamask" +import { + MetaMaskLikeProvider, + isMetaMask, + isMetaMaskLike, + requestNetworkSwitch, +} from "utils/metamask" + +type EthereumProvider = MetaMaskLikeProvider | UniversalProvider -export class MetaMaskSigner { +export class EthereumSigner { address: string - provider: MetaMaskLikeProvider + provider: EthereumProvider signer: JsonRpcSigner - constructor(address: string, provider: MetaMaskLikeProvider) { + constructor(address: string, provider: EthereumProvider) { this.address = address this.provider = provider this.signer = this.getSigner(provider) } - getSigner(provider: MetaMaskLikeProvider) { + getSigner(provider: EthereumProvider) { return new Web3Provider(provider).getSigner() } @@ -46,13 +54,16 @@ export class MetaMaskSigner { ) => { const { chain, ...tx } = transaction const from = chain && evmChains[chain] ? chain : "hydradx" - await requestNetworkSwitch(this.provider, { - chain: from, - onSwitch: () => { - // update signer after network switch - this.signer = this.getSigner(this.provider) - }, - }) + + if (isMetaMask(this.provider) || isMetaMaskLike(this.provider)) { + await requestNetworkSwitch(this.provider, { + chain: from, + onSwitch: () => { + // update signer after network switch + this.signer = this.getSigner(this.provider) + }, + }) + } if (from === "hydradx") { const [gas, gasPrice] = await this.getGasValues(tx) diff --git a/src/sections/web3-connect/wallets/WalletConnect/WalletConnectSigner.ts b/src/sections/web3-connect/signer/PolkadotSigner.ts similarity index 97% rename from src/sections/web3-connect/wallets/WalletConnect/WalletConnectSigner.ts rename to src/sections/web3-connect/signer/PolkadotSigner.ts index daacb0cc4..ad8237393 100644 --- a/src/sections/web3-connect/wallets/WalletConnect/WalletConnectSigner.ts +++ b/src/sections/web3-connect/signer/PolkadotSigner.ts @@ -18,7 +18,7 @@ interface Signature { signature: HexString } -export class WalletConnectSigner implements Signer { +export class PolkadotSigner implements Signer { registry: TypeRegistry client: SignClient session: SessionTypes.Struct diff --git a/src/sections/web3-connect/wallets/MetaMask/MetaMask.ts b/src/sections/web3-connect/wallets/MetaMask.ts similarity index 95% rename from src/sections/web3-connect/wallets/MetaMask/MetaMask.ts rename to src/sections/web3-connect/wallets/MetaMask.ts index 3fe846893..44ef6c627 100644 --- a/src/sections/web3-connect/wallets/MetaMask/MetaMask.ts +++ b/src/sections/web3-connect/wallets/MetaMask.ts @@ -1,6 +1,6 @@ import { SubscriptionFn, Wallet, WalletAccount } from "@talismn/connect-wallets" import MetaMaskLogo from "assets/icons/MetaMask.svg" -import { MetaMaskSigner } from "sections/web3-connect/wallets/MetaMask/MetaMaskSigner" +import { EthereumSigner } from "sections/web3-connect/signer/EthereumSigner" import { shortenAccountAddress } from "utils/formatting" import { noop } from "utils/helpers" import { @@ -26,7 +26,7 @@ export class MetaMask implements Wallet { } _extension: Required | undefined - _signer: MetaMaskSigner | undefined + _signer: EthereumSigner | undefined onAccountsChanged: SubscriptionFn | undefined onChainChanged: ChainSubscriptionFn | undefined @@ -80,7 +80,7 @@ export class MetaMask implements Wallet { Array.isArray(addresses) && addresses.length > 0 ? addresses[0] : "" this._extension = metamask - this._signer = address ? new MetaMaskSigner(address, metamask) : undefined + this._signer = address ? new EthereumSigner(address, metamask) : undefined this.subscribeAccounts(this.onAccountsChanged) this.subscribeChain(this.onChainChanged) diff --git a/src/sections/web3-connect/wallets/MetaMask/index.ts b/src/sections/web3-connect/wallets/MetaMask/index.ts deleted file mode 100644 index ad0757cb4..000000000 --- a/src/sections/web3-connect/wallets/MetaMask/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { MetaMask } from "./MetaMask" -export { TalismanEvm } from "../TalismanEvm" diff --git a/src/sections/web3-connect/wallets/TalismanEvm.ts b/src/sections/web3-connect/wallets/TalismanEvm.ts index 826d02d03..38135b8be 100644 --- a/src/sections/web3-connect/wallets/TalismanEvm.ts +++ b/src/sections/web3-connect/wallets/TalismanEvm.ts @@ -1,5 +1,5 @@ import { isTalisman } from "utils/metamask" -import { MetaMask } from "./MetaMask/MetaMask" +import { MetaMask } from "./MetaMask" import TalismanLogo from "assets/icons/TalismanLogo.svg" diff --git a/src/sections/web3-connect/wallets/WalletConnect.ts b/src/sections/web3-connect/wallets/WalletConnect.ts new file mode 100644 index 000000000..bbf2dd699 --- /dev/null +++ b/src/sections/web3-connect/wallets/WalletConnect.ts @@ -0,0 +1,265 @@ +import { Wallet, WalletAccount } from "@talismn/connect-wallets" +import { WalletConnectModal } from "@walletconnect/modal" +import { SessionTypes } from "@walletconnect/types" +import { + IUniversalProvider, + NamespaceConfig, + UniversalProvider, +} from "@walletconnect/universal-provider" +import WalletConnectLogo from "assets/icons/WalletConnect.svg" +import { POLKADOT_APP_NAME } from "utils/api" +import { evmChains } from "@galacticcouncil/xcm-sdk" +import { EthereumSigner } from "sections/web3-connect/signer/EthereumSigner" +import { isEvmAddress } from "utils/evm" +import { shortenAccountAddress } from "utils/formatting" +import { + PolkadotNamespaceChainId, + PolkadotSigner, +} from "sections/web3-connect/signer/PolkadotSigner" + +const WC_LS_KEY_PREFIX = "wc@2" +const WC_PROJECT_ID = import.meta.env.VITE_WC_PROJECT_ID as string +const DOMAIN_URL = import.meta.env.VITE_DOMAIN_URL as string + +const HDX_EVM_CHAIN_ID = import.meta.env.VITE_EVM_CHAIN_ID +const HDX_EVM_NAMESPACE_CHAIN_ID = `eip155:${HDX_EVM_CHAIN_ID}` +const HDX_POLKADOT_NAMESPACE_CHAIN_ID = import.meta.env + .VITE_HDX_CAIP_ID as string as PolkadotNamespaceChainId + +const walletConnectParams = { + projectId: WC_PROJECT_ID, + relayUrl: "wss://relay.walletconnect.com", + logger: "debug", + metadata: { + name: POLKADOT_APP_NAME, + description: POLKADOT_APP_NAME, + url: DOMAIN_URL, + icons: ["https://walletconnect.com/walletconnect-logo.png"], + }, +} + +const namespaces = { + eip155: { + chains: [HDX_EVM_NAMESPACE_CHAIN_ID], + methods: [ + "eth_sendTransaction", + "eth_signTransaction", + "eth_sign", + "personal_sign", + "eth_signTypedData", + ], + events: ["chainChanged", "accountsChanged"], + rpcMap: { + [HDX_EVM_CHAIN_ID]: evmChains["hydradx"].rpcUrls.default.http[0], + }, + }, + polkadot: { + methods: ["polkadot_signTransaction", "polkadot_signMessage"], + chains: [HDX_POLKADOT_NAMESPACE_CHAIN_ID], + events: ["accountsChanged", "disconnect"], + }, +} + +export type NamespaceType = keyof typeof namespaces + +const provider = await UniversalProvider.init(walletConnectParams) + +type ModalSubFn = (session?: SessionTypes.Struct) => void + +export class WalletConnect implements Wallet { + extensionName = "walletconnect" + title = "WalletConnect" + installUrl = "" + logo = { + src: WalletConnectLogo, + alt: "WalletConnect Logo", + } + + _modal: WalletConnectModal | undefined + _extension: IUniversalProvider | undefined + _signer: PolkadotSigner | EthereumSigner | undefined + _session: SessionTypes.Struct | undefined + _namespace: NamespaceConfig | undefined + + constructor({ + onModalOpen, + onModalClose, + }: { + onModalOpen?: ModalSubFn + onModalClose?: ModalSubFn + } = {}) { + this._modal = new WalletConnectModal({ + projectId: WC_PROJECT_ID, + }) + + this.subscribeToProviderEvents() + this.subscribeToModalEvents(onModalOpen, onModalClose) + } + + get extension() { + return this._extension + } + + get signer() { + return this._signer + } + + get modal() { + return this._modal + } + + get namespace() { + return this._namespace + } + + get installed() { + return true + } + + get rawExtension() { + return provider + } + + transformError = (err: Error): Error => { + return err + } + + setNamespace = async (namespace: keyof typeof namespaces) => { + this._namespace = { + [namespace]: namespaces[namespace], + } + } + + getChains = () => { + if (!this.namespace) return [] + + return Object.values(this.namespace) + .map((namespace) => namespace.chains) + .flat() + } + + subscribeToModalEvents = (onOpen?: ModalSubFn, onClose?: ModalSubFn) => { + this.modal?.subscribeModal((state) => { + if (state.open) { + onOpen?.() + } else { + onClose?.(this._session) + + if (!this._session) { + this.disconnect() + } + } + }) + } + + onDisplayUri = async (uri: string) => { + await this.modal?.openModal({ uri, chains: this.getChains() }) + } + + onSessionUpdate = ({ session }: { session: SessionTypes.Struct }) => { + this._session = session + } + + subscribeToProviderEvents = () => { + const provider = this.rawExtension + + provider.on("display_uri", this.onDisplayUri) + provider.on("session_update", this.onSessionUpdate) + } + + enable = async (dappName: string) => { + if (!dappName) { + throw new Error("MissingParamsError: Dapp name is required.") + } + + if (!this.namespace) { + throw new Error( + "WalletConnectError: Namespace is required to enable WalletConnect.", + ) + } + + try { + const provider = this.rawExtension + + const session = await provider.connect({ + namespaces: this.namespace, + pairingTopic: + "c4354cd737e7beaf736fc6692538e887bc1c118e4ae035d5efa2ed1f16819fb9", + }) + + if (!session) { + throw new Error( + "WalletConnectError: Failed to connect to WalletConnect.", + ) + } + + this._extension = provider + this._session = session + + const accounts = await this.getAccounts() + + const namespace = Object.keys(this.namespace).pop() as NamespaceType + + if (namespace === "eip155") { + const mainAddress = accounts[0]?.address + this._signer = mainAddress + ? new EthereumSigner(mainAddress, this.rawExtension) + : undefined + } + + if (namespace === "polkadot") { + this._signer = new PolkadotSigner( + provider.client, + session, + HDX_POLKADOT_NAMESPACE_CHAIN_ID, + ) + } + } catch (err) { + console.log({ err }) + } finally { + this.modal?.closeModal() + } + } + + getAccounts = async (): Promise => { + if (!this._session) { + throw new Error( + `The 'Wallet.enable(dappname)' function should be called first.`, + ) + } + + const wcAccounts = Object.values(this._session.namespaces) + .map((namespace) => namespace.accounts) + .flat() + + // return only first (active) account + return wcAccounts.slice(0, 1).map((wcAccount) => { + const address = wcAccount.split(":")[2] + return { + address, + source: this.extensionName, + name: isEvmAddress(address) + ? shortenAccountAddress(address) + : this.title, + wallet: this, + signer: this.signer, + } + }) + } + + subscribeAccounts = async () => {} + + disconnect = () => { + this._signer = undefined + this._session = undefined + this._namespace = undefined + this._extension = undefined + + // delete every WalletConnect v2 entry in local storage to forget the session + Object.keys(localStorage).forEach((key) => { + if (key.startsWith(WC_LS_KEY_PREFIX)) { + localStorage.removeItem(key) + } + }) + } +} diff --git a/src/sections/web3-connect/wallets/WalletConnect/WalletConnect.ts b/src/sections/web3-connect/wallets/WalletConnect/WalletConnect.ts deleted file mode 100644 index b680fa2cc..000000000 --- a/src/sections/web3-connect/wallets/WalletConnect/WalletConnect.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { Wallet, WalletAccount } from "@talismn/connect-wallets" -import { WalletConnectModal } from "@walletconnect/modal" -import { SessionTypes } from "@walletconnect/types" -import { - IUniversalProvider, - UniversalProvider, -} from "@walletconnect/universal-provider" -import WalletConnectLogo from "assets/icons/WalletConnect.svg" -import { - PolkadotNamespaceChainId, - WalletConnectSigner, -} from "sections/web3-connect/wallets/WalletConnect/WalletConnectSigner" -import { POLKADOT_APP_NAME } from "utils/api" - -const WC_PROJECT_ID = import.meta.env.VITE_WC_PROJECT_ID as string -const DOMAIN_URL = import.meta.env.VITE_DOMAIN_URL as string -const HYDRADX_CHAIN_ID = import.meta.env - .VITE_HDX_CAIP_ID as string as PolkadotNamespaceChainId - -const walletConnectParams = { - projectId: WC_PROJECT_ID, - relayUrl: "wss://relay.walletconnect.com", - metadata: { - name: POLKADOT_APP_NAME, - description: POLKADOT_APP_NAME, - url: DOMAIN_URL, - icons: ["https://walletconnect.com/walletconnect-logo.png"], - }, -} - -const requiredNamespaces = { - polkadot: { - methods: ["polkadot_signTransaction", "polkadot_signMessage"], - chains: [HYDRADX_CHAIN_ID], - events: ["accountsChanged", "disconnect"], - }, -} - -const chains = Object.values(requiredNamespaces) - .map((namespace) => namespace.chains) - .flat() - -const modal = new WalletConnectModal({ - projectId: WC_PROJECT_ID, - chains, -}) - -const provider = await UniversalProvider.init(walletConnectParams) - -export class WalletConnect implements Wallet { - extensionName = "walletconnect" - title = "WalletConnect" - installUrl = "" - logo = { - src: WalletConnectLogo, - alt: "WalletConnect Logo", - } - - _extension: IUniversalProvider | undefined - _signer: WalletConnectSigner | undefined - _session: SessionTypes.Struct | undefined - - constructor({ - onModalOpen, - onModalClose, - }: { - onModalOpen?: () => void - onModalClose?: () => void - } = {}) { - modal.subscribeModal((state) => { - state.open ? onModalOpen?.() : onModalClose?.() - }) - } - - get extension() { - return this._extension - } - - get signer() { - return this._signer - } - - get installed() { - return true - } - - get rawExtension() { - return provider - } - - transformError = (err: Error): Error => { - return err - } - - enable = async (dappName: string) => { - if (!dappName) { - throw new Error("MissingParamsError: Dapp name is required.") - } - - try { - const { uri, approval } = await this.rawExtension.client.connect({ - requiredNamespaces, - }) - - if (uri) { - await modal.openModal({ uri, chains }) - } - - const session = await approval() - - const client = this.rawExtension.client - - this._extension = this.rawExtension - this._session = session - this._signer = new WalletConnectSigner(client, session, HYDRADX_CHAIN_ID) - } finally { - modal.closeModal() - } - } - - getAccounts = async (): Promise => { - if (!this._session) { - throw new Error( - `The 'Wallet.enable(dappname)' function should be called first.`, - ) - } - - const wcAccounts = Object.values(this._session.namespaces) - .map((namespace) => namespace.accounts) - .flat() - - return wcAccounts.map((wcAccount) => { - const address = wcAccount.split(":")[2] - return { - address, - source: this.extensionName, - name: this.title, - wallet: this, - signer: this.signer, - } - }) - } - - subscribeAccounts = async () => {} -} diff --git a/src/sections/web3-connect/wallets/WalletConnect/index.ts b/src/sections/web3-connect/wallets/WalletConnect/index.ts deleted file mode 100644 index 9a246b88a..000000000 --- a/src/sections/web3-connect/wallets/WalletConnect/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { WalletConnect } from "./WalletConnect" diff --git a/src/sections/web3-connect/wallets/index.ts b/src/sections/web3-connect/wallets/index.ts index 3e6036c38..a84731fee 100644 --- a/src/sections/web3-connect/wallets/index.ts +++ b/src/sections/web3-connect/wallets/index.ts @@ -1,9 +1,4 @@ -import { - SubscriptionFn, - Wallet, - WalletAccount, - getWallets, -} from "@talismn/connect-wallets" +import { SubscriptionFn, Wallet, getWallets } from "@talismn/connect-wallets" import { ExternalWallet } from "./ExternalWallet" import { MetaMask } from "./MetaMask" @@ -63,7 +58,14 @@ const metaMask: Wallet = new MetaMask({ onAccountsChanged: onMetaMaskLikeAccountChange(WalletProviderType.MetaMask), }) -const walletConnect: Wallet = new WalletConnect() +const walletConnect: Wallet = new WalletConnect({ + onModalClose: (session) => { + if (!session) { + const state = useWeb3ConnectStore.getState() + state.disconnect() + } + }, +}) const externalWallet: Wallet = new ExternalWallet() diff --git a/src/utils/metamask.ts b/src/utils/metamask.ts index 23e5a9c1e..bfa0849c7 100644 --- a/src/utils/metamask.ts +++ b/src/utils/metamask.ts @@ -84,7 +84,8 @@ export async function requestNetworkSwitch( .then(options?.onSwitch) } catch (error: any) { // missing or unsupported network error - if (error?.code === 4902) { + const errorCode = error.data?.originalError?.code || error?.code + if (errorCode === 4902) { try { await provider .request({ From 3fa0ccd9413111ccb9a1afeff65663d7bcbbd9f3 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Tue, 9 Apr 2024 10:36:23 +0200 Subject: [PATCH 002/103] XYK farms --- .../modals/join/JoinFarmsModal.styled.ts | 3 + .../farms/modals/join/JoinFarmsModal.tsx | 153 +++++++++++------- .../farms/modals/join/JoinFarmsModal.utils.ts | 40 +++++ .../position/redeposit/RedepositFarms.tsx | 2 +- .../pool/positions/LiquidityPosition.tsx | 4 +- .../pool/xykPosition/JoinFarmsButton.tsx | 80 +++++++++ .../pools/pool/xykPosition/XYKPosition.tsx | 13 +- src/utils/balance.ts | 10 +- 8 files changed, 232 insertions(+), 73 deletions(-) create mode 100644 src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts create mode 100644 src/sections/pools/pool/xykPosition/JoinFarmsButton.tsx diff --git a/src/sections/pools/farms/modals/join/JoinFarmsModal.styled.ts b/src/sections/pools/farms/modals/join/JoinFarmsModal.styled.ts index c7e2e79c8..ba2058018 100644 --- a/src/sections/pools/farms/modals/join/JoinFarmsModal.styled.ts +++ b/src/sections/pools/farms/modals/join/JoinFarmsModal.styled.ts @@ -2,6 +2,9 @@ import styled from "@emotion/styled" import { theme } from "theme" export const SJoinFarmContainer = styled.div` + display: flex; + flex-direction: column; + background: rgba(${theme.rgbColors.darkBlue900}, 0.4); margin: 16px calc(-1 * var(--modal-content-padding)) diff --git a/src/sections/pools/farms/modals/join/JoinFarmsModal.tsx b/src/sections/pools/farms/modals/join/JoinFarmsModal.tsx index eb4060abc..22daa6a5f 100644 --- a/src/sections/pools/farms/modals/join/JoinFarmsModal.tsx +++ b/src/sections/pools/farms/modals/join/JoinFarmsModal.tsx @@ -17,14 +17,17 @@ import { SJoinFarmContainer } from "./JoinFarmsModal.styled" import { useBestNumber } from "api/chain" import { useRpcProvider } from "providers/rpcProvider" import { Alert } from "components/Alert/Alert" -import { Spacer } from "components/Spacer/Spacer" -import { BN_0 } from "utils/constants" +import { Controller, useForm } from "react-hook-form" +import { scaleHuman } from "utils/balance" +import { WalletTransferAssetSelect } from "sections/wallet/transfer/WalletTransferAssetSelect" +import { useZodSchema } from "./JoinFarmsModal.utils" +import { zodResolver } from "@hookform/resolvers/zod" type JoinFarmModalProps = { isOpen: boolean onClose: () => void poolId: string - shares?: BigNumber + initialShares?: BigNumber farms: Farm[] isRedeposit?: boolean mutation?: FarmDepositMutationType | FarmRedepositMutationType @@ -37,7 +40,7 @@ export const JoinFarmModal = ({ isRedeposit, poolId, mutation, - shares, + initialShares, depositNft, farms, }: JoinFarmModalProps) => { @@ -50,25 +53,24 @@ export const JoinFarmModal = ({ const meta = assets.getAsset(poolId.toString()) const bestNumber = useBestNumber() + const zodSchema = useZodSchema(meta.id, farms) + + const form = useForm<{ amount: string }>({ + mode: "onChange", + defaultValues: { + amount: initialShares + ? scaleHuman(initialShares, meta.decimals).toString() + : undefined, + }, + resolver: zodSchema ? zodResolver(zodSchema) : undefined, + }) + const selectedFarm = farms.find( (farm) => farm.globalFarm.id.eq(selectedFarmId?.globalFarmId) && farm.yieldFarm.id.eq(selectedFarmId?.yieldFarmId), ) - const { isValid, minDeposit } = farms.reduce<{ - isValid: boolean - minDeposit: BigNumber - }>( - (acc, farm) => { - const minDeposit = farm.globalFarm.minDeposit.toBigNumber() - const isValid = !!shares?.gte(minDeposit) - - return { isValid, minDeposit: !isValid ? minDeposit : acc.minDeposit } - }, - { isValid: false, minDeposit: BN_0 }, - ) - const { page, direction, back, next } = useModalPagination() const onBack = () => { @@ -82,8 +84,12 @@ export const JoinFarmModal = ({ selectedFarm?.globalFarm.blocksPerPeriod.toNumber() ?? 1, ) + const onSubmit = () => mutation?.mutate() + + const error = form.formState.errors.amount?.message + return ( - + - {mutation && shares && ( - -
-
- {t("farms.modal.footer.title")} -
- + + {initialShares ? ( +
+
+ {t("farms.modal.footer.title")} +
+ + {t("value.token", { + value: initialShares, + fixedPointScale: meta.decimals, + })} + +
+ ) : ( + ( + + )} + /> + )} + + {error && initialShares && ( + + {error} + + )} + +
- {!isValid && ( - <> - - {t("farms.modal.join.minDeposit", { - value: minDeposit.shiftedBy(-meta.decimals), - })} - - - - )} - -
+ + + )} ), diff --git a/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts b/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts new file mode 100644 index 000000000..e528d5cb6 --- /dev/null +++ b/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts @@ -0,0 +1,40 @@ +import { z } from "zod" +import { maxBalance, required } from "utils/validators" +import { useTokenBalance } from "api/balances" +import { useAccount } from "sections/web3-connect/Web3Connect.utils" +import { useRpcProvider } from "providers/rpcProvider" +import { BN_0 } from "utils/constants" +import { Farm } from "api/farms" +import { useMemo } from "react" +import { scale, scaleHuman } from "utils/balance" +import i18n from "i18next" +import BN from "bignumber.js" + +export const useZodSchema = (id: string, farms: Farm[]) => { + const { account } = useAccount() + const { assets } = useRpcProvider() + const { data: balance } = useTokenBalance(id, account?.address) + + const meta = assets.getAsset(id) + + const minDeposit = useMemo(() => { + return farms.reduce((acc, farm) => { + const minDeposit = farm.globalFarm.minDeposit.toBigNumber() + + return minDeposit.gt(acc) ? minDeposit : acc + }, BN(10000000)) + }, [farms]) + + if (!balance) return undefined + + return z.object({ + amount: required + .pipe(maxBalance(balance?.balance ?? BN_0, meta.decimals)) + .refine( + (value) => scale(value, meta.decimals).gte(minDeposit), + i18n.t("farms.modal.join.minDeposit", { + value: scaleHuman(minDeposit, meta.decimals), + }), + ), + }) +} diff --git a/src/sections/pools/farms/position/redeposit/RedepositFarms.tsx b/src/sections/pools/farms/position/redeposit/RedepositFarms.tsx index bec2fc256..eb18930ed 100644 --- a/src/sections/pools/farms/position/redeposit/RedepositFarms.tsx +++ b/src/sections/pools/farms/position/redeposit/RedepositFarms.tsx @@ -91,7 +91,7 @@ export const RedepositFarms = ({ depositNft, poolId }: RedepositFarmsProps) => { farms={availableYieldFarms} isOpen={joinFarm} poolId={poolId} - shares={depositNft.data.shares.toBigNumber()} + initialShares={depositNft.data.shares.toBigNumber()} mutation={redeposit} onClose={() => setJoinFarm(false)} isRedeposit diff --git a/src/sections/pools/pool/positions/LiquidityPosition.tsx b/src/sections/pools/pool/positions/LiquidityPosition.tsx index d2390cde5..c6c769182 100644 --- a/src/sections/pools/pool/positions/LiquidityPosition.tsx +++ b/src/sections/pools/pool/positions/LiquidityPosition.tsx @@ -77,7 +77,7 @@ function LiquidityPositionJoinFarmButton(props: { variant="primary" size="compact" fullWidth - disabled={!farms.data?.length || account?.isExternalWalletConnected} + //disabled={!farms.data?.length || account?.isExternalWalletConnected} onClick={() => setJoinFarm(true)} > } /> @@ -89,7 +89,7 @@ function LiquidityPositionJoinFarmButton(props: { farms={farms.data} isOpen={joinFarm} poolId={props.poolId} - shares={props.position.shares} + initialShares={props.position.shares} onClose={() => setJoinFarm(false)} mutation={joinFarmMutation} /> diff --git a/src/sections/pools/pool/xykPosition/JoinFarmsButton.tsx b/src/sections/pools/pool/xykPosition/JoinFarmsButton.tsx new file mode 100644 index 000000000..06ecfab34 --- /dev/null +++ b/src/sections/pools/pool/xykPosition/JoinFarmsButton.tsx @@ -0,0 +1,80 @@ +import { useFarms } from "api/farms" +import { Button } from "components/Button/Button" +import { Icon } from "components/Icon/Icon" +import { useRpcProvider } from "providers/rpcProvider" +import { useState } from "react" +import { Trans, useTranslation } from "react-i18next" +import { useAccount } from "sections/web3-connect/Web3Connect.utils" +import { ToastMessage } from "state/store" +import { TOAST_MESSAGES } from "state/toasts" +import { useFarmDepositMutation } from "utils/farms/deposit" +import FPIcon from "assets/icons/PoolsAndFarms.svg?react" +import { JoinFarmModal } from "sections/pools/farms/modals/join/JoinFarmsModal" +import { BN_0 } from "utils/constants" + +const shares = BN_0 +const positionId = "0" + +export const JoinFarmsButton = (props: { + poolId: string + onSuccess: () => void +}) => { + const { t } = useTranslation() + const { assets } = useRpcProvider() + const { account } = useAccount() + const [joinFarm, setJoinFarm] = useState(false) + const farms = useFarms([props.poolId]) + const meta = assets.getAsset(props.poolId.toString()) + + const toast = TOAST_MESSAGES.reduce((memo, type) => { + const msType = type === "onError" ? "onLoading" : type + memo[type] = ( + + + + + ) + return memo + }, {} as ToastMessage) + + const joinFarmMutation = useFarmDepositMutation( + props.poolId, + positionId, + toast, + () => setJoinFarm(false), + props.onSuccess, + ) + + return ( + <> + + + {joinFarm && farms.data && ( + setJoinFarm(false)} + mutation={joinFarmMutation} + /> + )} + + ) +} diff --git a/src/sections/pools/pool/xykPosition/XYKPosition.tsx b/src/sections/pools/pool/xykPosition/XYKPosition.tsx index ada948899..8854915c7 100644 --- a/src/sections/pools/pool/xykPosition/XYKPosition.tsx +++ b/src/sections/pools/pool/xykPosition/XYKPosition.tsx @@ -18,6 +18,7 @@ import { LiquidityPositionRemoveLiquidity } from "sections/pools/pool/positions/ import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { useMedia } from "react-use" import { theme } from "theme" +import { JoinFarmsButton } from "./JoinFarmsButton" export const XYKPosition = ({ pool }: { pool: TXYKPool }) => { const { t } = useTranslation() @@ -107,11 +108,13 @@ export const XYKPosition = ({ pool }: { pool: TXYKPool }) => { })} - - null} - /> +
+ null} /> + null} + /> +
diff --git a/src/utils/balance.ts b/src/utils/balance.ts index 4d2b2c0eb..4c8268f24 100644 --- a/src/utils/balance.ts +++ b/src/utils/balance.ts @@ -1,5 +1,5 @@ import { BN } from "@polkadot/util" -import { BN_10, QUINTILL, TRILL } from "./constants" +import { BN_10, BN_NAN, QUINTILL, TRILL } from "./constants" import BigNumber from "bignumber.js" import { BigNumberFormatOptionsSchema, @@ -51,9 +51,11 @@ export const getFixedPointAmount = ( * eg.: 1.23456789 => 123456789 */ export const scale = ( - amount: BigNumberLikeType, + amount: BigNumberLikeType | undefined, decimals: number | "t" | "q", ) => { + if (!amount) return BN_NAN + const _decimals = decimals === "t" ? TRILL : decimals === "q" ? QUINTILL : decimals @@ -68,9 +70,11 @@ export const scale = ( * eg.: 123456789 => 1.23456789 */ export const scaleHuman = ( - amount: BigNumberLikeType, + amount: BigNumberLikeType | undefined, decimals: number | "t" | "q", ) => { + if (!amount) return BN_NAN + const _decimals = decimals === "t" ? TRILL : decimals === "q" ? QUINTILL : decimals From 47e0437e55345a818972f1cb594f8273a74f05b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Wed, 10 Apr 2024 14:58:42 +0200 Subject: [PATCH 003/103] Show TX link for all states of transaction --- src/components/Toast/Toast.styled.ts | 10 +--- src/components/Toast/ToastContent.tsx | 8 +-- src/components/Toast/sidebar/ToastSidebar.tsx | 1 + .../transaction/ReviewTransaction.tsx | 3 +- .../transaction/ReviewTransaction.utils.tsx | 51 ++++++++----------- .../transaction/ReviewTransactionToast.tsx | 3 ++ src/utils/evm.ts | 13 +++++ 7 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/components/Toast/Toast.styled.ts b/src/components/Toast/Toast.styled.ts index 7fb534632..f876b172a 100644 --- a/src/components/Toast/Toast.styled.ts +++ b/src/components/Toast/Toast.styled.ts @@ -42,17 +42,11 @@ export const SIcon = styled.div` } ` -export const SLink = styled.div<{ variant: ToastVariant }>` +export const SLink = styled.div` display: flex; align-items: center; justify-content: center; - color: ${({ variant }) => { - if (variant === "progress") { - return theme.colors.white - } - - return `rgba(${theme.rgbColors.white}, 0.6)` - }}; + color: rgba(${theme.rgbColors.white}, 0.6); svg { width: 16px; diff --git a/src/components/Toast/ToastContent.tsx b/src/components/Toast/ToastContent.tsx index 431f31680..1fd553556 100644 --- a/src/components/Toast/ToastContent.tsx +++ b/src/components/Toast/ToastContent.tsx @@ -69,13 +69,13 @@ export function ToastContent(props: { - - {props.link && ( + {props.link && ( + - )} - + + )} {props.children} ) diff --git a/src/components/Toast/sidebar/ToastSidebar.tsx b/src/components/Toast/sidebar/ToastSidebar.tsx index 35df6ae3a..c9d5d7a28 100644 --- a/src/components/Toast/sidebar/ToastSidebar.tsx +++ b/src/components/Toast/sidebar/ToastSidebar.tsx @@ -81,6 +81,7 @@ export function ToastSidebar() { {pendingToasts.map((toast) => ( { data, txState, reset, + txLink, } = useSendTx() const isError = isSendError || !!signError @@ -84,7 +85,7 @@ export const ReviewTransaction = (props: Transaction) => { isSuccess={isSuccess} isError={isError} error={error} - link={data?.transactionLink} + link={txLink} onReview={onReview} onClose={onClose} toastMessage={props.toastMessage} diff --git a/src/sections/transaction/ReviewTransaction.utils.tsx b/src/sections/transaction/ReviewTransaction.utils.tsx index 45857bae4..71087c050 100644 --- a/src/sections/transaction/ReviewTransaction.utils.tsx +++ b/src/sections/transaction/ReviewTransaction.utils.tsx @@ -2,14 +2,12 @@ import { TransactionReceipt, TransactionResponse, } from "@ethersproject/providers" -import { evmChains } from "@galacticcouncil/xcm-sdk" import { Hash } from "@open-web3/orml-types/interfaces" import { SubmittableExtrinsic } from "@polkadot/api/types" import type { AnyJson } from "@polkadot/types-codec/types" import { ExtrinsicStatus } from "@polkadot/types/interfaces" import { ISubmittableResult } from "@polkadot/types/types" import { MutationObserverOptions, useMutation } from "@tanstack/react-query" -import { useTransactionLink } from "api/transaction" import { decodeError } from "ethers-decode-error" import { useRpcProvider } from "providers/rpcProvider" import { useRef, useState } from "react" @@ -17,7 +15,8 @@ import { useTranslation } from "react-i18next" import { useMountedState } from "react-use" import { useEvmAccount } from "sections/web3-connect/Web3Connect.utils" import { useToast } from "state/toasts" -import { H160, getEvmTxLink, isEvmAccount } from "utils/evm" +import { H160, getEvmChainById, getEvmTxLink, isEvmAccount } from "utils/evm" +import { getSubscanLinkByType } from "utils/formatting" type TxMethod = AnyJson & { method: string @@ -107,9 +106,7 @@ function evmTxReceiptToSubmittableResult(txReceipt: TransactionReceipt) { } export const useSendEvmTransactionMutation = ( options: MutationObserverOptions< - ISubmittableResult & { - transactionLink?: string - }, + ISubmittableResult, unknown, { evmTx: TransactionResponse @@ -118,6 +115,8 @@ export const useSendEvmTransactionMutation = ( > = {}, ) => { const [txState, setTxState] = useState(null) + const [txHash, setTxHash] = useState("") + const { account } = useEvmAccount() const sendTx = useMutation(async ({ evmTx }) => { @@ -132,21 +131,11 @@ export const useSendEvmTransactionMutation = ( try { setTxState("Broadcast") + setTxHash(evmTx?.hash ?? "") const receipt = await evmTx.wait() setTxState("InBlock") - const chainEntries = Object.entries(evmChains).find( - ([_, chain]) => chain.id === account?.chainId, - ) - - const chain = chainEntries?.[0] - - const transactionLink = getEvmTxLink(receipt.transactionHash, chain) - - return resolve({ - transactionLink, - ...evmTxReceiptToSubmittableResult(receipt), - }) + return resolve(evmTxReceiptToSubmittableResult(receipt)) } catch (err) { const { error } = decodeError(err) reject(new Error(error)) @@ -156,11 +145,16 @@ export const useSendEvmTransactionMutation = ( }) }, options) + const chain = account?.chainId ? getEvmChainById(account.chainId) : null + const txLink = txHash && chain ? getEvmTxLink(txHash, chain.key) : "" + return { ...sendTx, txState, + txLink, reset: () => { setTxState(null) + setTxHash("") sendTx.reset() }, } @@ -168,15 +162,15 @@ export const useSendEvmTransactionMutation = ( export const useSendTransactionMutation = ( options: MutationObserverOptions< - ISubmittableResult & { transactionLink?: string }, + ISubmittableResult, unknown, SubmittableExtrinsic<"promise"> > = {}, ) => { const { api } = useRpcProvider() const isMounted = useMountedState() - const link = useTransactionLink() const [txState, setTxState] = useState(null) + const [txHash, setTxHash] = useState("") const sendTx = useMutation(async (sign) => { return await new Promise(async (resolve, reject) => { @@ -190,6 +184,7 @@ export const useSendTransactionMutation = ( }, 60000) if (isMounted()) { + setTxHash(result.txHash.toHex()) setTxState(result.status.type) } else { clearTimeout(timeout) @@ -211,16 +206,8 @@ export const useSendTransactionMutation = ( clearTimeout(timeout) reject(new Error(errorMessage)) } else { - const transactionLink = await link.mutateAsync({ - blockHash: result.status.asInBlock.toString(), - txIndex: result.txIndex?.toString(), - }) - clearTimeout(timeout) - resolve({ - transactionLink, - ...result, - }) + resolve(result) } unsubscribe() @@ -232,11 +219,17 @@ export const useSendTransactionMutation = ( }) }, options) + const txLink = txHash + ? `${getSubscanLinkByType("extrinsic")}/${txHash}` + : undefined + return { ...sendTx, txState, + txLink, reset: () => { setTxState(null) + setTxHash("") sendTx.reset() }, } diff --git a/src/sections/transaction/ReviewTransactionToast.tsx b/src/sections/transaction/ReviewTransactionToast.tsx index 04297a7de..97fc15115 100644 --- a/src/sections/transaction/ReviewTransactionToast.tsx +++ b/src/sections/transaction/ReviewTransactionToast.tsx @@ -48,12 +48,14 @@ export function ReviewTransactionToast(props: { if (isError) { if (error instanceof UnknownTransactionState) { toastRef.current.unknown({ + link: props.link, title: props.toastMessage?.onError ?? (

{t("liquidity.reviewTransaction.toast.unknown")}

), }) } else { toastRef.current.error({ + link: props.link, title: props.toastMessage?.onError ?? (

{t("liquidity.reviewTransaction.toast.error")}

), @@ -63,6 +65,7 @@ export function ReviewTransactionToast(props: { if (isLoading) { toRemoveId = toastRef.current.loading({ + link: props.link, title: props.toastMessage?.onLoading ?? (

{t("liquidity.reviewTransaction.toast.pending")}

), diff --git a/src/utils/evm.ts b/src/utils/evm.ts index 268f63839..6a682f650 100644 --- a/src/utils/evm.ts +++ b/src/utils/evm.ts @@ -72,4 +72,17 @@ export function safeConvertAddressH160(value: string): string | null { } } +export function getEvmChainById(chainId: number) { + const entries = Object.entries(evmChains).find( + ([_, chain]) => chain.id === chainId, + ) + const [key, chain] = entries ?? [] + if (key) { + return { + key, + ...chain, + } + } +} + export { getEvmAddress, isEvmAddress } From ecf4a07d3354cfdc0fbc6052c4f96cae647a9284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Wed, 10 Apr 2024 16:44:52 +0200 Subject: [PATCH 004/103] OTC order price column update --- src/i18n/locales/en/translations.json | 3 ++- src/sections/trade/sections/otc/orders/OtcOrdersData.tsx | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/i18n/locales/en/translations.json b/src/i18n/locales/en/translations.json index 86eb35b97..1f171876e 100644 --- a/src/i18n/locales/en/translations.json +++ b/src/i18n/locales/en/translations.json @@ -367,7 +367,8 @@ "otc.offers.table.header.offer": "Offer", "otc.offers.table.header.accepting": "Accepting", "otc.offers.table.header.assets": "Assets", - "otc.offers.table.header.orderPrice": "Order Price", + "otc.offers.table.header.orderPrice": "Offer USD Price", + "otc.offers.table.header.perToken": "per {{ symbol }}", "otc.offers.table.header.marketPrice": "Market Price", "otc.offers.table.header.status": "Order status", "otc.offers.table.actions.fill": "Fill order", diff --git a/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx b/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx index fc7a0b40e..c7bdb0f7e 100644 --- a/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx +++ b/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx @@ -176,10 +176,14 @@ export const OrderPriceColumn = (props: { pair: OfferingPair; price: BN }) => { ) : ( <> - {t("value.token", { value: 1 })} {props.pair.symbol} + {abbreviateNumber(props.price)} - ({abbreviateNumber(props.price)}) + ( + {t("otc.offers.table.header.perToken", { + symbol: props.pair.symbol, + })} + ) )} From 732b684946370b7b2d0593158caf9974a9e8ec87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Thu, 11 Apr 2024 11:31:16 +0200 Subject: [PATCH 005/103] Removed pairing topic --- src/sections/web3-connect/wallets/WalletConnect.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sections/web3-connect/wallets/WalletConnect.ts b/src/sections/web3-connect/wallets/WalletConnect.ts index bbf2dd699..edec1d707 100644 --- a/src/sections/web3-connect/wallets/WalletConnect.ts +++ b/src/sections/web3-connect/wallets/WalletConnect.ts @@ -183,8 +183,6 @@ export class WalletConnect implements Wallet { const session = await provider.connect({ namespaces: this.namespace, - pairingTopic: - "c4354cd737e7beaf736fc6692538e887bc1c118e4ae035d5efa2ed1f16819fb9", }) if (!session) { From 6b70acf6a30eb8c12dcc2423c73a4029bc486c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Thu, 11 Apr 2024 11:32:34 +0200 Subject: [PATCH 006/103] typo --- src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx b/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx index 6272d1463..a6ced0bf6 100644 --- a/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx +++ b/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx @@ -76,7 +76,7 @@ export const Web3ConnectWCSelector: React.FC< enable("polkadot") }} > - SUBSRTATE + SUBSTRATE )} From 6dfb88c8e53482ff235859a634acfb12104e29c3 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Fri, 12 Apr 2024 10:50:16 +0200 Subject: [PATCH 007/103] wip --- src/api/provider.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/api/provider.ts b/src/api/provider.ts index 37fa9242c..0f13439ee 100644 --- a/src/api/provider.ts +++ b/src/api/provider.ts @@ -5,6 +5,7 @@ import { create } from "zustand" import { persist } from "zustand/middleware" import { getAssets } from "./assetDetails" import { SubstrateApis } from "@galacticcouncil/xcm-sdk" +import { ApiPromise, WsProvider } from "@polkadot/api" export const PROVIDERS = [ { @@ -99,8 +100,12 @@ export const useProviderData = (rpcUrl: string) => { return useQuery( QUERY_KEYS.provider(rpcUrl), async ({ queryKey: [_, url] }) => { - const apiPool = SubstrateApis.getInstance() - const api = await apiPool.api(url) + //const apiPool = SubstrateApis.getInstance() + const provider = new WsProvider(url) + + const api = await ApiPromise.create({ + provider, + }) const { isStableCoin, From a53f8ef2d7827f36759ab59e93cbe7bba884c382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Fri, 12 Apr 2024 11:06:42 +0200 Subject: [PATCH 008/103] WalletConnect multichain onboarding --- .../web3-connect/constants/providers.ts | 10 ++++++ .../providers/Web3ConnectProviders.tsx | 22 ++++++++++--- .../providers/Web3ConnectWCSelector.tsx | 20 +++++++++--- .../web3-connect/signer/PolkadotSigner.ts | 18 +++++------ .../web3-connect/wallets/WalletConnect.ts | 32 +++++++++++++------ src/sections/web3-connect/wallets/index.ts | 1 + 6 files changed, 75 insertions(+), 28 deletions(-) diff --git a/src/sections/web3-connect/constants/providers.ts b/src/sections/web3-connect/constants/providers.ts index 2096dacae..30316fbb5 100644 --- a/src/sections/web3-connect/constants/providers.ts +++ b/src/sections/web3-connect/constants/providers.ts @@ -23,6 +23,16 @@ export const DESKTOP_PROVIDERS: WalletProviderType[] = [ export const EVM_PROVIDERS: WalletProviderType[] = [ WalletProviderType.MetaMask, WalletProviderType.TalismanEvm, + WalletProviderType.WalletConnect, +] + +export const SUBSTRATE_PROVIDERS: WalletProviderType[] = [ + WalletProviderType.Talisman, + WalletProviderType.SubwalletJS, + WalletProviderType.Enkrypt, + WalletProviderType.PolkadotJS, + WalletProviderType.NovaWallet, + WalletProviderType.WalletConnect, ] export const ALTERNATIVE_PROVIDERS: WalletProviderType[] = [ diff --git a/src/sections/web3-connect/providers/Web3ConnectProviders.tsx b/src/sections/web3-connect/providers/Web3ConnectProviders.tsx index 4b35da335..a11a8da7e 100644 --- a/src/sections/web3-connect/providers/Web3ConnectProviders.tsx +++ b/src/sections/web3-connect/providers/Web3ConnectProviders.tsx @@ -15,9 +15,11 @@ import { DESKTOP_PROVIDERS, EVM_PROVIDERS, MOBILE_PROVIDERS, + SUBSTRATE_PROVIDERS, } from "sections/web3-connect/constants/providers" +import { POLKADOT_CAIP_ID_MAP } from "sections/web3-connect/wallets/WalletConnect" -const useWalletProviders = (mode: WalletMode) => { +const useWalletProviders = (mode: WalletMode, chain?: string) => { const isDesktop = useMedia(theme.viewport.gte.sm) return useMemo(() => { @@ -34,13 +36,19 @@ const useWalletProviders = (mode: WalletMode) => { : MOBILE_PROVIDERS.includes(provider.type) const isEvmProvider = EVM_PROVIDERS.includes(provider.type) + const isSubstrateProvider = SUBSTRATE_PROVIDERS.includes(provider.type) const byMode = isDefaultMode || (isEvmMode && isEvmProvider) || - (isSubstrateMode && !isEvmProvider) + (isSubstrateMode && isSubstrateProvider) - return byScreen && byMode + const byWalletConnect = + isSubstrateMode && provider.type === "walletconnect" && chain + ? !!POLKADOT_CAIP_ID_MAP[chain] + : true + + return byScreen && byMode && byWalletConnect }) const alternativeProviders = wallets.filter((provider) => { @@ -52,15 +60,19 @@ const useWalletProviders = (mode: WalletMode) => { defaultProviders, alternativeProviders, } - }, [isDesktop, mode]) + }, [isDesktop, mode, chain]) } export const Web3ConnectProviders = () => { const { t } = useTranslation() const mode = useWeb3ConnectStore(useShallow((state) => state.mode)) + const meta = useWeb3ConnectStore(useShallow((state) => state.meta)) - const { defaultProviders, alternativeProviders } = useWalletProviders(mode) + const { defaultProviders, alternativeProviders } = useWalletProviders( + mode, + meta?.chain, + ) return ( <> diff --git a/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx b/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx index a6ced0bf6..2a15925f9 100644 --- a/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx +++ b/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx @@ -24,9 +24,13 @@ const getWalletConnect = () => { export const Web3ConnectWCSelector: React.FC< Web3ConnectWCSelectorProps > = () => { - const { setStatus, setError, provider, status, account } = + const { setStatus, setError, provider, status, account, mode } = useWeb3ConnectStore() + const isDefaultMode = mode === "default" + const isEvmMode = mode === "evm" + const isSubstrateMode = mode === "substrate" + const { enable, isLoading } = useEnableWallet(walletConnectType, { onSuccess: () => setStatus(walletConnectType, WalletProviderStatus.Connected), @@ -47,14 +51,22 @@ export const Web3ConnectWCSelector: React.FC< const isSessionActive = !!wallet?._session - const shouldTriggerAutoConnect = isConnectedToWc && !isSessionActive + const shouldTriggerAutoConnect = + (isConnectedToWc && !isSessionActive) || isEvmMode || isSubstrateMode useEffect(() => { if (shouldTriggerAutoConnect) { - const isEvm = isEvmAccount(account?.address) + const isEvm = + (isDefaultMode && isEvmAccount(account?.address)) || isEvmMode enable(isEvm ? "eip155" : "polkadot") } - }, [account?.address, enable, shouldTriggerAutoConnect]) + }, [ + account?.address, + enable, + isDefaultMode, + isEvmMode, + shouldTriggerAutoConnect, + ]) return (
diff --git a/src/sections/web3-connect/signer/PolkadotSigner.ts b/src/sections/web3-connect/signer/PolkadotSigner.ts index ad8237393..7d6908812 100644 --- a/src/sections/web3-connect/signer/PolkadotSigner.ts +++ b/src/sections/web3-connect/signer/PolkadotSigner.ts @@ -8,6 +8,8 @@ import type { import type { HexString } from "@polkadot/util/types" import SignClient from "@walletconnect/sign-client" import { SessionTypes, SignClientTypes } from "@walletconnect/types" +import { POLKADOT_CAIP_ID_MAP } from "sections/web3-connect/wallets/WalletConnect" +import { genesisHashToChain } from "utils/helpers" export type KeypairType = "ed25519" | "sr25519" export type WcAccount = `${string}:${string}:${string}` @@ -22,25 +24,22 @@ export class PolkadotSigner implements Signer { registry: TypeRegistry client: SignClient session: SessionTypes.Struct - chainId: PolkadotNamespaceChainId id = 0 - constructor( - client: SignClient, - session: SessionTypes.Struct, - chainId: PolkadotNamespaceChainId, - ) { + constructor(client: SignClient, session: SessionTypes.Struct) { this.client = client this.session = session this.registry = new TypeRegistry() - this.chainId = chainId } // this method is set this way to be bound to this class. signPayload = async (payload: SignerPayloadJSON): Promise => { + const chain = genesisHashToChain(payload.genesisHash as `0x${string}`) + const chainId = POLKADOT_CAIP_ID_MAP[chain?.network] + let request = { topic: this.session.topic, - chainId: this.chainId, + chainId, request: { id: 1, jsonrpc: "2.0", @@ -56,9 +55,10 @@ export class PolkadotSigner implements Signer { // It might be used outside of the object context to sign messages. // ref: https://polkadot.js.org/docs/extension/cookbook#sign-a-message signRaw = async (raw: SignerPayloadRaw): Promise => { + const chainId = POLKADOT_CAIP_ID_MAP["hydradx"] let request = { topic: this.session.topic, - chainId: this.chainId, + chainId, request: { id: 1, jsonrpc: "2.0", diff --git a/src/sections/web3-connect/wallets/WalletConnect.ts b/src/sections/web3-connect/wallets/WalletConnect.ts index edec1d707..7fe0a1876 100644 --- a/src/sections/web3-connect/wallets/WalletConnect.ts +++ b/src/sections/web3-connect/wallets/WalletConnect.ts @@ -23,8 +23,26 @@ const DOMAIN_URL = import.meta.env.VITE_DOMAIN_URL as string const HDX_EVM_CHAIN_ID = import.meta.env.VITE_EVM_CHAIN_ID const HDX_EVM_NAMESPACE_CHAIN_ID = `eip155:${HDX_EVM_CHAIN_ID}` -const HDX_POLKADOT_NAMESPACE_CHAIN_ID = import.meta.env - .VITE_HDX_CAIP_ID as string as PolkadotNamespaceChainId + +export const POLKADOT_CAIP_ID_MAP: Record = { + hydradx: import.meta.env + .VITE_HDX_CAIP_ID as string as PolkadotNamespaceChainId, + polkadot: "polkadot:91b171bb158e2d3848fa23a9f1c25182", + acala: "polkadot:fc41b9bd8ef8fe53d58c7ea67c794c7e", + assethub: "polkadot:68d56f15f85d3136970ec16946040bc1", + astar: "polkadot:9eb76c5184c4ab8679d2d5d819fdf90b", + bifrost: "polkadot:262e1b2ad728475fd6fe88e62d34c200", + centrifuge: "polkadot:b3db41421702df9a7fcac62b53ffeac8", + crust: "polkadot:4319cc49ee79495b57a1fec4d2bd43f5", + interlay: "polkadot:bf88efe70e9e0e916416e8bed61f2b45", + nodle: "polkadot:97da7ede98d7bad4e36b4d734b605542", + phala: "polkadot:1bb969d85965e4bb5a651abbedf21a54", + subsocial: "polkadot:4a12be580bb959937a1c7a61d5cf2442", + unique: "polkadot:84322d9cddbf35088f1e54e9a85c967a", + zeitgeist: "polkadot:1bf2a2ecb4a868de66ea8610f2ce7c8c", +} + +const POLKADOT_CHAIN_IDS = Object.values(POLKADOT_CAIP_ID_MAP) const walletConnectParams = { projectId: WC_PROJECT_ID, @@ -55,7 +73,7 @@ const namespaces = { }, polkadot: { methods: ["polkadot_signTransaction", "polkadot_signMessage"], - chains: [HDX_POLKADOT_NAMESPACE_CHAIN_ID], + chains: POLKADOT_CHAIN_IDS, events: ["accountsChanged", "disconnect"], }, } @@ -206,14 +224,8 @@ export class WalletConnect implements Wallet { } if (namespace === "polkadot") { - this._signer = new PolkadotSigner( - provider.client, - session, - HDX_POLKADOT_NAMESPACE_CHAIN_ID, - ) + this._signer = new PolkadotSigner(provider.client, session) } - } catch (err) { - console.log({ err }) } finally { this.modal?.closeModal() } diff --git a/src/sections/web3-connect/wallets/index.ts b/src/sections/web3-connect/wallets/index.ts index a84731fee..3b6d7de47 100644 --- a/src/sections/web3-connect/wallets/index.ts +++ b/src/sections/web3-connect/wallets/index.ts @@ -63,6 +63,7 @@ const walletConnect: Wallet = new WalletConnect({ if (!session) { const state = useWeb3ConnectStore.getState() state.disconnect() + state.toggle() } }, }) From e49a1bd1cc35523981f0352c78bfbab1310d0df3 Mon Sep 17 00:00:00 2001 From: Pavol Noha Date: Fri, 12 Apr 2024 15:52:48 +0200 Subject: [PATCH 009/103] Upgrade apps, ui, sdk -> external sync/STINK --- package.json | 6 +++--- yarn.lock | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index ce6f93661..4451f214c 100644 --- a/package.json +++ b/package.json @@ -31,15 +31,15 @@ "@emotion/styled": "^11.10.4", "@ethersproject/address": "^5.7.0", "@ethersproject/providers": "^5.7.2", - "@galacticcouncil/apps": "3.4.11", + "@galacticcouncil/apps": "3.5.0", "@galacticcouncil/math-lbp": "^0.2.1", "@galacticcouncil/math-liquidity-mining": "^0.2.0", "@galacticcouncil/math-omnipool": "^0.2.0", "@galacticcouncil/math-stableswap": "^0.2.2", "@galacticcouncil/math-staking": "^0.2.0", "@galacticcouncil/math-xyk": "^0.2.0", - "@galacticcouncil/sdk": "^2.1.0", - "@galacticcouncil/ui": "^3.1.5", + "@galacticcouncil/sdk": "^2.2.1", + "@galacticcouncil/ui": "^3.1.6", "@galacticcouncil/xcm-cfg": "^1.11.3", "@galacticcouncil/xcm-sdk": "^2.4.0", "@hookform/resolvers": "^3.3.4", diff --git a/yarn.lock b/yarn.lock index dc098b11d..ddc547acb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2997,10 +2997,10 @@ resolved "https://registry.yarnpkg.com/@galacticcouncil/api-augment/-/api-augment-0.0.6.tgz#fc54c04c3bb953db3f739ea2c5820153088d564d" integrity sha512-5Qq+dzRoyuMS6uUXjl1asRrosIQ1n0vD0dzbxK8H8f3hmIzDdpiQVqlqWBLEc7D/PA7VM/7j1scICpdjtJJELw== -"@galacticcouncil/apps@3.4.11": - version "3.4.11" - resolved "https://registry.yarnpkg.com/@galacticcouncil/apps/-/apps-3.4.11.tgz#40e8874e5bffae9e7123cf338f7871bf6f1b7148" - integrity sha512-fftkcTMtIitB30OcN198HuaLw/iMzVTzZr9hPY+hujSGgoeqUksTc5pIZx+ootPtBmORQfswIFCRX+GgdH20hA== +"@galacticcouncil/apps@3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@galacticcouncil/apps/-/apps-3.5.0.tgz#1d480e37fb994a4252883697332ca2cee1e2fa2e" + integrity sha512-H4Sv8obIjvOSZffFa8XP+ZZlcWJnvAPCTacN7/d860xClh3yLA2ciYE/cxeu3B+V22z3kUKWNwcw9IqoR++KbQ== dependencies: "@cfx-kit/wallet-avatar" "0.0.5" "@thi.ng/atom" "^5.1.3" @@ -3043,10 +3043,10 @@ resolved "https://registry.yarnpkg.com/@galacticcouncil/math-xyk/-/math-xyk-0.2.0.tgz#74feacdf94d4846f1a148835f25936b2ddc7bdfd" integrity sha512-mznedOeA8d9BQ8kUQ/4O/P6trqTC4FGwvTDGCHJ0O/bgA9iFb+suctbFtyFT3qfNnngR7FSF2Pls1O/SvtNn8g== -"@galacticcouncil/sdk@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@galacticcouncil/sdk/-/sdk-2.1.0.tgz#44280daa444b8f0c1d45cda579449d19e20dd2ac" - integrity sha512-JIyym2q7UlEOZxoMtNTocW3Mxgg5vRqYdPGQVk4uYDTC5883635iGnW5COcbaxMwOteR/reKbswv49qyTsgKdw== +"@galacticcouncil/sdk@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@galacticcouncil/sdk/-/sdk-2.2.1.tgz#ad6df6785c103125daab52a1d5b1bb9859b96bc2" + integrity sha512-jdrQ2qtEy2a51xG3qHJvDR4xjEh5JTl6KLtCz0FZgTE2ppRQqCnBXveG+gHduPA0VNGK1I5qIfVQWlHot8ucTw== dependencies: "@galacticcouncil/math-lbp" "^0.2.1" "@galacticcouncil/math-omnipool" "^0.2.0" @@ -3056,10 +3056,10 @@ bignumber.js "^9.1.0" lodash.clonedeep "^4.5.0" -"@galacticcouncil/ui@^3.1.5": - version "3.1.5" - resolved "https://registry.yarnpkg.com/@galacticcouncil/ui/-/ui-3.1.5.tgz#2450b424d51239e2cd89b32da4981e10b25478c0" - integrity sha512-qPgukXwa6fFa7oyzQWBUFTUrgOUlrvYIU+JgA+UB5pMpjAIIivrJpL4NDo8pMpUdtpm7QEizzWbBDsqMogdqEQ== +"@galacticcouncil/ui@^3.1.6": + version "3.1.6" + resolved "https://registry.yarnpkg.com/@galacticcouncil/ui/-/ui-3.1.6.tgz#9748d2ac9644263da0839cf85aad5b4593f83375" + integrity sha512-uLBNdrPen7Jzy43pBwsbB21ovWtmoOJuB6vJw9hNQPAqZ+WoYeC9llCi/rItY2B63oP6GBwrx+oOL8zcjtF2Qw== dependencies: "@floating-ui/dom" "^1.5.1" "@lit/reactive-element" "^1.0.0" From 73f09757c2ef637b5fcb3833b75b20ea33689a4e Mon Sep 17 00:00:00 2001 From: Pavol Noha Date: Fri, 12 Apr 2024 15:53:41 +0200 Subject: [PATCH 010/103] AppsPersistenceProvider support --- src/components/AppProviders/AppProviders.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/AppProviders/AppProviders.tsx b/src/components/AppProviders/AppProviders.tsx index b3feab5b7..547fdef41 100644 --- a/src/components/AppProviders/AppProviders.tsx +++ b/src/components/AppProviders/AppProviders.tsx @@ -6,6 +6,15 @@ import { FC, PropsWithChildren } from "react" import { SkeletonTheme } from "react-loading-skeleton" import { Transactions } from "sections/transaction/Transactions" import { theme } from "theme" +import * as React from "react" +import * as Apps from "@galacticcouncil/apps" +import { createComponent } from "@lit-labs/react" + +const AppsPersistenceProvider = createComponent({ + tagName: "gc-database-provider", + elementClass: Apps.DatabaseProvider, + react: React, +}) export const AppProviders: FC = ({ children }) => { return ( @@ -18,7 +27,7 @@ export const AppProviders: FC = ({ children }) => { highlightColor={`rgba(${theme.rgbColors.white}, 0.24)`} borderRadius={4} > - {children} + {children} From e4533b501db6b611e5f0dbb5cea24f88f9d3f0f6 Mon Sep 17 00:00:00 2001 From: Pavol Noha Date: Fri, 12 Apr 2024 15:53:59 +0200 Subject: [PATCH 011/103] Sync external tokens update with apps state --- src/sections/wallet/addToken/AddToken.utils.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sections/wallet/addToken/AddToken.utils.tsx b/src/sections/wallet/addToken/AddToken.utils.tsx index 64eeaa619..276c3a75b 100644 --- a/src/sections/wallet/addToken/AddToken.utils.tsx +++ b/src/sections/wallet/addToken/AddToken.utils.tsx @@ -1,4 +1,5 @@ import { useMutation } from "@tanstack/react-query" +import { ExternalAssetCursor } from "@galacticcouncil/apps" import { useRpcProvider } from "providers/rpcProvider" import { ToastMessage, useStore } from "state/store" import { HydradxRuntimeXcmAssetLocation } from "@polkadot/types/lookup" @@ -122,7 +123,14 @@ export const useUserExternalTokenStore = create()( }, ], addToken: (token) => - set((store) => ({ tokens: [...store.tokens, token] })), + set((store) => { + const latest = { tokens: [...store.tokens, token] } + ExternalAssetCursor.reset({ + state: latest, + version: 0.2, + }) + return latest + }), isAdded: (id) => id ? get().tokens.some((token) => token.id === id) : false, }), From 1292b2613f17b03ce0fef0d11ec3cb64e7f2e636 Mon Sep 17 00:00:00 2001 From: Pavol Noha Date: Fri, 12 Apr 2024 16:41:18 +0200 Subject: [PATCH 012/103] Fix warning icon stop offsets --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4451f214c..47822f325 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@galacticcouncil/math-staking": "^0.2.0", "@galacticcouncil/math-xyk": "^0.2.0", "@galacticcouncil/sdk": "^2.2.1", - "@galacticcouncil/ui": "^3.1.6", + "@galacticcouncil/ui": "^3.1.7", "@galacticcouncil/xcm-cfg": "^1.11.3", "@galacticcouncil/xcm-sdk": "^2.4.0", "@hookform/resolvers": "^3.3.4", diff --git a/yarn.lock b/yarn.lock index ddc547acb..31c5040c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3056,10 +3056,10 @@ bignumber.js "^9.1.0" lodash.clonedeep "^4.5.0" -"@galacticcouncil/ui@^3.1.6": - version "3.1.6" - resolved "https://registry.yarnpkg.com/@galacticcouncil/ui/-/ui-3.1.6.tgz#9748d2ac9644263da0839cf85aad5b4593f83375" - integrity sha512-uLBNdrPen7Jzy43pBwsbB21ovWtmoOJuB6vJw9hNQPAqZ+WoYeC9llCi/rItY2B63oP6GBwrx+oOL8zcjtF2Qw== +"@galacticcouncil/ui@^3.1.7": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@galacticcouncil/ui/-/ui-3.1.7.tgz#88f7fc57ac4b763ecb94ddc9694aeaac742e0143" + integrity sha512-dR7i7ucbIrT+ub6ITF7l7gRw/HGOueoBTCeRc7O7AJHKNj+oY/yefzpX/i7/aQChSjsHrNgsKQKM2IBxk00Hlg== dependencies: "@floating-ui/dom" "^1.5.1" "@lit/reactive-element" "^1.0.0" From 60cc321bfe5a5cdf2a1fb3317b5e89992d936215 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Fri, 12 Apr 2024 17:34:47 +0200 Subject: [PATCH 013/103] wip --- src/api/assetDetails.ts | 6 +- src/api/deposits.ts | 127 ++---- src/api/farms.ts | 389 +++++++++--------- src/api/provider.ts | 20 +- .../Layout/Header/menu/HeaderMenu.tsx | 4 +- src/providers/rpcProvider.tsx | 10 +- src/sections/pools/PoolsPage.utils.ts | 165 +++++++- .../pools/farms/FarmingPositionWrapper.tsx | 6 +- .../farms/modals/join/JoinFarmsButton.tsx | 45 ++ .../farms/modals/join/JoinFarmsModal.tsx | 117 +++--- .../joinedFarmDetails/JoinedFarmsDetails.tsx | 1 + .../pools/farms/position/FarmingPosition.tsx | 192 ++++++--- .../farms/position/FarmingPosition.utils.tsx | 20 +- src/sections/pools/navigation/Navigation.tsx | 4 +- src/sections/pools/pool/Pool.tsx | 3 +- .../pool/availableFarms/AvailableFarms.tsx | 4 +- .../pools/pool/myPositions/MyPositions.tsx | 11 +- .../pool/positions/LiquidityPosition.tsx | 76 +--- .../pool/xykPosition/JoinFarmsButton.tsx | 80 ---- .../pools/pool/xykPosition/XYKPosition.tsx | 4 +- .../WalletFarmingPositions.utils.tsx | 36 +- .../WalletAssetsHydraPositionsData.utils.tsx | 4 +- src/utils/farms/claiming.ts | 56 +-- src/utils/farms/{deposit.ts => deposit.tsx} | 70 +++- src/utils/farms/exit.ts | 20 +- src/utils/queryKeys.ts | 46 +-- 26 files changed, 808 insertions(+), 708 deletions(-) create mode 100644 src/sections/pools/farms/modals/join/JoinFarmsButton.tsx delete mode 100644 src/sections/pools/pool/xykPosition/JoinFarmsButton.tsx rename src/utils/farms/{deposit.ts => deposit.tsx} (51%) diff --git a/src/api/assetDetails.ts b/src/api/assetDetails.ts index bb3139857..dd1f1a6f7 100644 --- a/src/api/assetDetails.ts +++ b/src/api/assetDetails.ts @@ -113,7 +113,7 @@ export type TStableSwap = TAssetCommon & { export type TShareToken = TAssetCommon & { assetType: "ShareToken" assets: string[] - poolAddress: string | undefined + poolAddress: string } export type TAsset = TToken | TBond | TStableSwap | TShareToken @@ -441,9 +441,9 @@ export const getAssets = async (api: ApiPromise) => { (token) => token.id === assetBId, ) as TToken - const isValdiTokens = assetA?.name && assetB?.name + const isValidTokens = assetA?.name && assetB?.name - if (isValdiTokens) { + if (isValidTokens) { const assetDecimal = Number(assetA.id) > Number(assetB.id) ? assetB : assetA diff --git a/src/api/deposits.ts b/src/api/deposits.ts index e1609d872..5df295268 100644 --- a/src/api/deposits.ts +++ b/src/api/deposits.ts @@ -1,63 +1,52 @@ import { ApiPromise } from "@polkadot/api" -import { u128, u32 } from "@polkadot/types" -import { AccountId32 } from "@polkadot/types/interfaces" +import { u128, u32, Option } from "@polkadot/types" import { useQueries, useQuery } from "@tanstack/react-query" -import { useAccount } from "sections/web3-connect/Web3Connect.utils" -import { Maybe, undefinedNoop, useQueryReduce } from "utils/helpers" import { QUERY_KEYS } from "utils/queryKeys" import { useRpcProvider } from "providers/rpcProvider" +import { useAccountNFTPositions } from "sections/pools/PoolsPage.utils" +import { PalletLiquidityMiningDepositData } from "@polkadot/types/lookup" -const DEPOSIT_NFT_COLLECTION_ID = "2584" - -export const useAccountDepositIds = ( - accountId: Maybe, -) => { +export const useOmnipoolDeposits = (ids: string[]) => { const { api } = useRpcProvider() + return useQuery( - QUERY_KEYS.accountDepositIds(accountId), - accountId != null ? getAccountDepositIds(api, accountId) : undefinedNoop, - { enabled: !!accountId }, + QUERY_KEYS.omnipoolDeposits(ids), + getDeposits(api, "omnipool", ids), + { enabled: !!ids.length }, ) } -const getAccountDepositIds = - (api: ApiPromise, accountId: AccountId32 | string) => async () => { - const res = await api.query.uniques.account.entries( - accountId, - DEPOSIT_NFT_COLLECTION_ID, - ) - const nfts = res.map(([storageKey]) => { - const [owner, classId, instanceId] = storageKey.args - return { owner, classId, instanceId } - }) - - return nfts - } - -export const useAllDeposits = () => { +export const useXYKDeposits = (ids: string[]) => { const { api } = useRpcProvider() - return useQuery(QUERY_KEYS.allDeposits, getDeposits(api)) -} -export const usePoolDeposits = (poolId?: u32 | string) => { - const { api } = useRpcProvider() - return useQuery(QUERY_KEYS.poolDeposits(poolId), getDeposits(api), { - enabled: !!poolId, - select: (data) => - data.filter( - (item) => item.data.ammPoolId.toString() === poolId?.toString(), - ), + return useQuery(QUERY_KEYS.xykDeposits(ids), getDeposits(api, "xyk", ids), { + enabled: !!ids.length, }) } -export const useOmniPositionId = (positionId: u128 | string) => { - const { api } = useRpcProvider() +const getDeposits = + (api: ApiPromise, type: "omnipool" | "xyk", ids: string[]) => async () => { + if (!ids.length) return undefined - return useQuery( - QUERY_KEYS.omniPositionId(positionId), - getOmniPositionId(api, positionId), - ) -} + const keys = ids.map((id) => + api.query[`${type}WarehouseLM`].deposit.key(id), + ) + const values = (await api.rpc.state.queryStorageAt( + keys, + )) as Option[] + + const data = values.map( + (value) => + api.registry.createType( + type === "omnipool" ? "OmnipoolLMDeposit" : "XykLMDeposit", + value.unwrap(), + ) as PalletLiquidityMiningDepositData, + ) + + const test = ids.map((id, i) => ({ id, data: data[i] })) + + return test + } export const useOmniPositionIds = (positionIds: Array) => { const { api } = useRpcProvider() @@ -70,15 +59,6 @@ export const useOmniPositionIds = (positionIds: Array) => { })), }) } - -const getDeposits = (api: ApiPromise) => async () => { - const res = await api.query.omnipoolWarehouseLM.deposit.entries() - return res.map(([key, value]) => ({ - id: key.args[0], - data: value.unwrap(), - })) -} - const getOmniPositionId = (api: ApiPromise, depositionId: u128 | string) => async () => { const res = @@ -86,38 +66,17 @@ const getOmniPositionId = return { depositionId, value: res.value } } -export const useAccountDeposits = (poolId?: u32) => { - const { account } = useAccount() - const accountDepositIds = useAccountDepositIds(account?.address) - const deposits = usePoolDeposits(poolId) - - return useQueryReduce( - [accountDepositIds, deposits] as const, - (accountDepositIds, deposits) => { - const ids = new Set( - accountDepositIds?.map((i) => i.instanceId.toString()), - ) - return deposits.filter((item) => ids.has(item.id.toString())) - }, - ) -} +export const useUserDeposits = (address?: string) => { + const nftPositions = useAccountNFTPositions(address) -export const useUserDeposits = () => { - const { account } = useAccount() - const accountDepositIds = useAccountDepositIds(account?.address) - const deposits = useAllDeposits() + const { miningNfts = [], xykMiningNfts = [] } = nftPositions.data ?? {} + const omnipoolDeposits = + useOmnipoolDeposits(miningNfts.map((miningNft) => miningNft.instanceId)) + .data ?? [] - const query = useQueryReduce( - [accountDepositIds, deposits] as const, - (accountDepositIds, deposits) => { - return deposits.filter( - (deposit) => - accountDepositIds?.some( - (id) => id.instanceId.toString() === deposit.id.toString(), - ), - ) - }, - ) + const xykDeposits = + useXYKDeposits(xykMiningNfts.map((xykMiningNft) => xykMiningNft.instanceId)) + .data ?? [] - return query + return { omnipoolDeposits, xykDeposits } } diff --git a/src/api/farms.ts b/src/api/farms.ts index d4bc9afd7..1e88102ee 100644 --- a/src/api/farms.ts +++ b/src/api/farms.ts @@ -8,8 +8,8 @@ import { import { useQueries, useQuery } from "@tanstack/react-query" import BigNumber from "bignumber.js" import { secondsInYear } from "date-fns" -import { BLOCK_TIME, BN_0, PARACHAIN_BLOCK_TIME } from "utils/constants" -import { Maybe, isNotNil, undefinedNoop, useQueryReduce } from "utils/helpers" +import { BLOCK_TIME, BN_0, BN_1, PARACHAIN_BLOCK_TIME } from "utils/constants" +import { undefinedNoop, useQueryReduce } from "utils/helpers" import { QUERY_KEYS } from "utils/queryKeys" import { useBestNumber } from "./chain" import { fixed_from_rational } from "@galacticcouncil/math-liquidity-mining" @@ -18,184 +18,186 @@ import { useRpcProvider } from "providers/rpcProvider" import { useIndexerUrl } from "./provider" import request, { gql } from "graphql-request" import { AccountId32 } from "@polkadot/types/interfaces" +import { useMemo } from "react" const NEW_YIELD_FARMS_BLOCKS = (48 * 60 * 60) / PARACHAIN_BLOCK_TIME.toNumber() // 48 hours -export function useActiveYieldFarms(poolIds: Array>) { - const { api } = useRpcProvider() +type FarmIds = { + poolId: string + globalFarmId: string + yieldFarmId: string +} + +type FarmAprs = ReturnType + +export interface Farm { + globalFarm: PalletLiquidityMiningGlobalFarmData + yieldFarm: PalletLiquidityMiningYieldFarmData + poolId: string +} + +export const useFarmingPoolAssets = () => { + const { assets } = useRpcProvider() + + console.log(assets.tradeAssets, assets.shareTokens) +} + +export function useActiveYieldFarms(poolIds: Array) { + const { api, assets } = useRpcProvider() return useQueries({ - queries: poolIds.map((poolId) => ({ - queryKey: QUERY_KEYS.activeYieldFarms(poolId), - queryFn: - poolId != null ? getActiveYieldFarms(api, poolId) : undefinedNoop, - enabled: poolId != null, - })), + queries: poolIds.map((poolId) => { + const meta = assets.getAsset(poolId) + const isXYK = assets.isShareToken(meta) + + return { + queryKey: isXYK + ? QUERY_KEYS.activeYieldFarmsXYK(poolId) + : QUERY_KEYS.activeYieldFarms(poolId), + queryFn: getActiveYieldFarms( + api, + poolId, + isXYK ? meta.poolAddress : undefined, + ), + enabled: poolId != null, + } + }), }) } +const getActiveYieldFarms = + (api: ApiPromise, poolId: string, poolAddress: string | undefined) => + async () => { + const res = poolAddress + ? await api.query.xykWarehouseLM.activeYieldFarm.entries(poolAddress) + : await api.query.omnipoolWarehouseLM.activeYieldFarm.entries(poolId) -export const getActiveYieldFarms = - (api: ApiPromise, poolId: u32 | string) => async () => { - const res = - await api.query.omnipoolWarehouseLM.activeYieldFarm.entries(poolId) return res.map(([storageKey, codec]) => { - const [poolId, globalFarmId] = storageKey.args + const [, globalFarmId] = storageKey.args const yieldFarmId = codec.unwrap() - return { poolId, globalFarmId, yieldFarmId } + return { + poolId, + globalFarmId: globalFarmId.toString(), + yieldFarmId: yieldFarmId.toString(), + } }) } -export function useYieldFarms( - ids: Maybe< - { - poolId: u32 | string - globalFarmId: u32 | string - yieldFarmId: u32 | string - }[] - >, -) { - const { api } = useRpcProvider() - return useQuery( - QUERY_KEYS.yieldFarms(ids), - ids != null ? getYieldFarms(api, ids) : undefinedNoop, - { enabled: ids != null }, - ) -} +export function useYieldFarms(ids: FarmIds[]) { + const { api, assets } = useRpcProvider() -const getYieldFarms = - ( - api: ApiPromise, - ids: { - poolId: u32 | string - globalFarmId: u32 | string - yieldFarmId: u32 | string - }[], - ) => - async () => { - const res = await Promise.all( - ids.map(({ poolId, globalFarmId, yieldFarmId }) => - api.query.omnipoolWarehouseLM.yieldFarm( - poolId, + return useQueries({ + queries: ids.map(({ poolId, globalFarmId, yieldFarmId }) => { + const meta = assets.getAsset(poolId) + const isXYK = assets.isShareToken(meta) + + return { + queryKey: isXYK + ? QUERY_KEYS.yieldFarmXYK(poolId) + : QUERY_KEYS.yieldFarm(poolId), + queryFn: getYieldFarm( + api, + isXYK ? meta.poolAddress : poolId, globalFarmId, yieldFarmId, + isXYK, ), - ), - ) - - return res.map((data) => data.unwrap()) - } - -export function useYieldFarm(data: { - poolId: Maybe - globalFarmId: Maybe - yieldFarmId: Maybe -}) { - const { api } = useRpcProvider() - return useQuery( - QUERY_KEYS.yieldFarm(data), - data.poolId != null && data.globalFarmId != null && data.yieldFarmId != null - ? getYieldFarm(api, data.poolId, data.globalFarmId, data.yieldFarmId) - : undefinedNoop, - { - enabled: - data.poolId != null && - data.globalFarmId != null && - data.yieldFarmId != null, - }, - ) + enabled: poolId != null, + } + }), + }) } const getYieldFarm = ( api: ApiPromise, - poolId: u32 | string, - globalFarmId: u32 | string, - yieldFarmId: u32 | string, + poolId: string, + globalFarmId: string, + yieldFarmId: string, + isXYK: boolean, ) => async () => { - const yieldFarm = await api.query.omnipoolWarehouseLM.yieldFarm( - poolId, - globalFarmId, - yieldFarmId, - ) + const yieldFarm = isXYK + ? await api.query.xykWarehouseLM.yieldFarm( + poolId, + globalFarmId, + yieldFarmId, + ) + : await api.query.omnipoolWarehouseLM.yieldFarm( + poolId, + globalFarmId, + yieldFarmId, + ) + return yieldFarm.unwrap() } -export function useGlobalFarm(id: Maybe) { - const { api } = useRpcProvider() - return useQuery( - QUERY_KEYS.globalFarm(id), - id != null ? getGlobalFarm(api, id) : undefinedNoop, - { enabled: id != null }, - ) -} +export function useGlobalFarms(ids: FarmIds[]) { + const { api, assets } = useRpcProvider() -const getGlobalFarm = (api: ApiPromise, id: u32 | string) => async () => { - const globalFarm = await api.query.omnipoolWarehouseLM.globalFarm(id) - return globalFarm.unwrap() + return useQueries({ + queries: ids.map(({ poolId, globalFarmId }) => { + const meta = assets.getAsset(poolId) + const isXYK = assets.isShareToken(meta) + + return { + queryKey: isXYK + ? QUERY_KEYS.globalFarmXYK(poolId) + : QUERY_KEYS.globalFarm(poolId), + queryFn: getGlobalFarm(api, globalFarmId, isXYK), + enabled: poolId != null, + } + }), + }) } -export function useGlobalFarms(ids: Maybe<{ globalFarmId: u32 }[]>) { - const { api } = useRpcProvider() - return useQuery( - QUERY_KEYS.globalFarms(ids), - ids != null ? getGlobalFarms(api, ids) : undefinedNoop, - { enabled: ids != null }, - ) -} +const getGlobalFarm = + (api: ApiPromise, id: string, isXYK: boolean) => async () => { + const globalFarm = isXYK + ? await api.query.xykWarehouseLM.globalFarm(id) + : await api.query.omnipoolWarehouseLM.globalFarm(id) -const getGlobalFarms = - (api: ApiPromise, ids: { globalFarmId: u32 }[]) => async () => { - const globalFarms = await api.query.omnipoolWarehouseLM.globalFarm.multi( - ids.map((i) => i.globalFarmId), - ) - return globalFarms.map((i) => i.unwrap()) + return globalFarm.unwrap() } -export interface Farm { - globalFarm: PalletLiquidityMiningGlobalFarmData - yieldFarm: PalletLiquidityMiningYieldFarmData - poolId: string -} +export const useFarms = (poolIds: Array) => { + const activeYieldFarmsQuery = useActiveYieldFarms(poolIds) -export type FarmAprs = ReturnType + const farmIds = activeYieldFarmsQuery + .reduce>>((acc, farm) => { + if (farm.data) acc.push(farm.data) + return acc + }, []) + .flat(2) -export type FarmQueryType = ReturnType + const globalFarms = useGlobalFarms(farmIds) + const yieldFarms = useYieldFarms(farmIds) -export const useFarms = (poolIds: Array) => { - const activeYieldFarms = useActiveYieldFarms(poolIds) + const queries = [globalFarms, yieldFarms] - const data = activeYieldFarms - .reduce( - (acc, farm) => { - if (farm.data) acc.push(farm.data) - return acc - }, - [] as Array>, - ) - .flat(2) + const isLoading = queries.some((querie) => + querie.some((q) => q.isInitialLoading), + ) - const globalFarms = useGlobalFarms(data) - const yieldFarms = useYieldFarms(data) + const data = useMemo(() => { + return farmIds + .map((farmId) => { + const globalFarm = globalFarms.find( + (globalFarm) => + globalFarm.data?.id.toString() === farmId.globalFarmId, + )?.data - return useQueryReduce( - [globalFarms, yieldFarms, ...activeYieldFarms] as const, - (globalFarms, yieldFarms, ...activeYieldFarms) => { - const farms = - activeYieldFarms.flat(2).map((af) => { - if (!af) return undefined - - const globalFarm = globalFarms?.find((gf) => - af.globalFarmId.eq(gf.id), - ) - const yieldFarm = yieldFarms?.find((yf) => af.yieldFarmId.eq(yf.id)) - if (!globalFarm || !yieldFarm) return undefined - return { globalFarm, yieldFarm, poolId: af.poolId.toString() } - }) ?? [] - - return farms.filter((x): x is Farm => x != null) - }, - ) + const yieldFarm = yieldFarms.find( + (yieldFarm) => yieldFarm.data?.id.toString() === farmId.yieldFarmId, + )?.data + + if (!globalFarm || !yieldFarm) return undefined + + return { globalFarm, yieldFarm, poolId: farmId.poolId } + }) + .filter((x): x is Farm => x != null) + }, [farmIds, globalFarms, yieldFarms]) + + return { data, isLoading } } function getGlobalRewardPerPeriod( @@ -340,16 +342,29 @@ export const useFarmApr = (farm: { yieldFarm: PalletLiquidityMiningYieldFarmData poolId: string }) => { + //const { assets } = useRpcProvider() const bestNumber = useBestNumber() const rewardCurrency = farm.globalFarm.rewardCurrency.toString() const incentivizedAsset = farm.globalFarm.incentivizedAsset.toString() + //const isXYK = assets.getAsset(farm.poolId).isShareToken + + // const oraclePrice = useOraclePrice( + // isXYK ? undefined : rewardCurrency, + // incentivizedAsset, + // ) + const oraclePrice = useOraclePrice(rewardCurrency, incentivizedAsset) return useQueryReduce( [bestNumber, oraclePrice] as const, (bestNumber, oraclePrice) => { - return getFarmApr(bestNumber, farm, oraclePrice?.oraclePrice ?? BN_0) + return getFarmApr( + bestNumber, + farm, + oraclePrice?.oraclePrice ?? + farm.globalFarm.priceAdjustment.toBigNumber(), + ) }, ) } @@ -380,7 +395,8 @@ export const useFarmAprs = ( return getFarmApr( bestNumber, farm, - oraclePrice?.data?.oraclePrice ?? BN_0, + oraclePrice?.data?.oraclePrice ?? + farm.globalFarm.priceAdjustment.toBigNumber(), ) }) }) @@ -426,12 +442,24 @@ const getOraclePrice = string, string, ] + + if (rewardCurrency === incentivizedAsset) + return { + id: { rewardCurrency, incentivizedAsset }, + oraclePrice: BN_1, + } const res = await api.query.emaOracle.oracles( "omnipool", orderedAssets, "TenMinutes", ) + if (res.isNone) + return { + id: { rewardCurrency, incentivizedAsset }, + oraclePrice: undefined, + } + const [data] = res.unwrap() const n = data.price.n.toString() const d = data.price.d.toString() @@ -464,12 +492,6 @@ export const getMinAndMaxAPR = (farms: FarmAprs) => { } } -export interface FarmIds { - poolId: u32 - globalFarmId: u32 - yieldFarmId: u32 -} - export const useFarmsPoolAssets = () => { const indexerUrl = useIndexerUrl() const { api } = useRpcProvider() @@ -533,35 +555,40 @@ export const useInactiveYieldFarms = (poolIds: (AccountId32 | string)[]) => { export const useInactiveFarms = (poolIds: Array) => { const activeYieldFarms = useInactiveYieldFarms(poolIds) - const data = activeYieldFarms.reduce< - { - poolId: string - globalFarmId: u32 - yieldFarmId: u32 - }[] - >((acc, farm) => (farm.data ? [...acc, ...farm.data] : acc), []) - - const globalFarms = useGlobalFarms( - data.map((id) => ({ globalFarmId: id.globalFarmId })), + const farmIds = activeYieldFarms.reduce( + (acc, farm) => (farm.data ? [...acc, ...farm.data] : acc), + [], ) - const yieldFarms = useYieldFarms(data) - return useQueryReduce( - [globalFarms, yieldFarms, ...activeYieldFarms] as const, - (globalFarms, yieldFarms, ...activeYieldFarms) => { - const farms = - activeYieldFarms.flat(2).map((af) => { - const globalFarm = globalFarms?.find((gf) => - af.globalFarmId.eq(gf.id), - ) - const yieldFarm = yieldFarms?.find((yf) => af.yieldFarmId.eq(yf.id)) - if (!globalFarm || !yieldFarm) return undefined - return { globalFarm, yieldFarm } - }) ?? [] - - return farms.filter(isNotNil) - }, + const globalFarms = useGlobalFarms(farmIds) + const yieldFarms = useYieldFarms(farmIds) + + const queries = [globalFarms, yieldFarms] + + const isLoading = queries.some((querie) => + querie.some((q) => q.isInitialLoading), ) + + const data = useMemo(() => { + return farmIds + .map((farmId) => { + const globalFarm = globalFarms.find( + (globalFarm) => + globalFarm.data?.id.toString() === farmId.globalFarmId, + )?.data + + const yieldFarm = yieldFarms.find( + (yieldFarm) => yieldFarm.data?.id.toString() === farmId.yieldFarmId, + )?.data + + if (!globalFarm || !yieldFarm) return undefined + + return { globalFarm, yieldFarm, poolId: farmId.poolId } + }) + .filter((x): x is Farm => x != null) + }, [farmIds, globalFarms, yieldFarms]) + + return { data, isLoading } } const getInctiveYieldFarms = @@ -582,13 +609,7 @@ const getInctiveYieldFarms = ), ) - const stoppedFarms = globalFarms.reduce< - { - poolId: string - globalFarmId: u32 - yieldFarmId: u32 - }[] - >((acc, [globalFarm]) => { + const stoppedFarms = globalFarms.reduce((acc, [globalFarm]) => { if (globalFarm) { const yieldFarm = globalFarm[1].unwrap() @@ -597,8 +618,8 @@ const getInctiveYieldFarms = if (isStopped) acc.push({ poolId: globalFarm[0].args[0].toString(), - globalFarmId: globalFarm[0].args[1], - yieldFarmId: yieldFarm.id, + globalFarmId: globalFarm[0].args[1].toString(), + yieldFarmId: yieldFarm.id.toString(), }) } diff --git a/src/api/provider.ts b/src/api/provider.ts index 0f13439ee..860e891f2 100644 --- a/src/api/provider.ts +++ b/src/api/provider.ts @@ -5,7 +5,6 @@ import { create } from "zustand" import { persist } from "zustand/middleware" import { getAssets } from "./assetDetails" import { SubstrateApis } from "@galacticcouncil/xcm-sdk" -import { ApiPromise, WsProvider } from "@polkadot/api" export const PROVIDERS = [ { @@ -100,11 +99,20 @@ export const useProviderData = (rpcUrl: string) => { return useQuery( QUERY_KEYS.provider(rpcUrl), async ({ queryKey: [_, url] }) => { - //const apiPool = SubstrateApis.getInstance() - const provider = new WsProvider(url) - - const api = await ApiPromise.create({ - provider, + const apiPool = SubstrateApis.getInstance() + const api = await apiPool.api(rpcUrl) + + api.registry.register({ + XykLMDeposit: { + shares: "u128", + ammPoolId: "AccountId", + yieldFarmEntries: "Vec", + }, + OmnipoolLMDeposit: { + shares: "u128", + ammPoolId: "u32", + yieldFarmEntries: "Vec", + }, }) const { diff --git a/src/components/Layout/Header/menu/HeaderMenu.tsx b/src/components/Layout/Header/menu/HeaderMenu.tsx index 81420e01b..2f3eea1b2 100644 --- a/src/components/Layout/Header/menu/HeaderMenu.tsx +++ b/src/components/Layout/Header/menu/HeaderMenu.tsx @@ -6,7 +6,7 @@ import { HeaderSubMenu } from "./HeaderSubMenu" import { forwardRef } from "react" import { useRpcProvider } from "providers/rpcProvider" import { useAccount } from "sections/web3-connect/Web3Connect.utils" -import { useAccountOmnipoolPositions } from "sections/pools/PoolsPage.utils" +import { useAccountNFTPositions } from "sections/pools/PoolsPage.utils" import { useTokensBalances } from "api/balances" export const HeaderMenu = forwardRef((_, ref) => { @@ -75,7 +75,7 @@ const LiquidityMenuItem = ({ const { t } = useTranslation() const { account } = useAccount() const { assets } = useRpcProvider() - const accountPositions = useAccountOmnipoolPositions() + const accountPositions = useAccountNFTPositions() const shareTokensId = assets.shareTokens.map((shareToken) => shareToken.id) const stableswapsId = assets.stableswap.map((shareToken) => shareToken.id) diff --git a/src/providers/rpcProvider.tsx b/src/providers/rpcProvider.tsx index 940df8c6b..d7b0fb81a 100644 --- a/src/providers/rpcProvider.tsx +++ b/src/providers/rpcProvider.tsx @@ -17,7 +17,7 @@ type IContextAssets = Awaited>["assets"] & { all: (TToken | TBond | TStableSwap | TShareToken)[] isStableSwap: (asset: TAsset) => asset is TStableSwap isBond: (asset: TAsset) => asset is TBond - isShareToken: (asset: TAsset) => asset is TShareToken + isShareToken: (asset: TAsset | undefined) => asset is TShareToken getAsset: (id: string) => TAsset getBond: (id: string) => TBond | undefined getAssets: (ids: string[]) => TAsset[] @@ -86,8 +86,12 @@ export const RpcProvider = ({ children }: { children: ReactNode }) => { const isBond = (asset: TAsset): asset is TBond => asset.isBond - const isShareToken = (asset: TAsset): asset is TShareToken => - asset.isShareToken + const isShareToken = ( + asset: TAsset | undefined, + ): asset is TShareToken => { + if (!asset) return false + return asset.isShareToken + } const getAsset = (id: string) => allTokensObject[id] ?? fallbackAsset diff --git a/src/sections/pools/PoolsPage.utils.ts b/src/sections/pools/PoolsPage.utils.ts index 6810831b3..412753709 100644 --- a/src/sections/pools/PoolsPage.utils.ts +++ b/src/sections/pools/PoolsPage.utils.ts @@ -42,6 +42,8 @@ import { is_remove_liquidity_allowed, is_sell_allowed, } from "@galacticcouncil/math-omnipool" +import { Option } from "@polkadot/types" +import { PalletLiquidityMiningDepositData } from "@polkadot/types/lookup" export const useAssetsTradability = () => { const { @@ -107,7 +109,7 @@ export const derivePoolAccount = (assetId: string) => { return encodeAddress(blake2AsHex(name), HYDRADX_SS58_PREFIX) } -export const useAccountOmnipoolPositions = (givenAddress?: string) => { +export const useAccountNFTPositions = (givenAddress?: string) => { const { account } = useAccount() const { api } = useRpcProvider() @@ -117,15 +119,18 @@ export const useAccountOmnipoolPositions = (givenAddress?: string) => { QUERY_KEYS.accountOmnipoolPositions(address), address != null ? async () => { - const [omnipoolNftId, miningNftId] = await Promise.all([ - api.consts.omnipool.nftCollectionId, - api.consts.omnipoolLiquidityMining.nftCollectionId, - ]) - - const [omnipoolNftsRaw, miningNftsRaw] = await Promise.all([ - api.query.uniques.account.entries(address, omnipoolNftId), - api.query.uniques.account.entries(address, miningNftId), - ]) + const [omnipoolNftId, miningNftId, xykMiningNftId] = + await Promise.all([ + api.consts.omnipool.nftCollectionId, + api.consts.omnipoolLiquidityMining.nftCollectionId, + api.consts.xykLiquidityMining.nftCollectionId, + ]) + const [omnipoolNftsRaw, miningNftsRaw, xykMiningNftsRaw] = + await Promise.all([ + api.query.uniques.account.entries(address, omnipoolNftId), + api.query.uniques.account.entries(address, miningNftId), + api.query.uniques.account.entries(address, xykMiningNftId), + ]) const omnipoolNfts = omnipoolNftsRaw.map(([storageKey]) => { const [owner, classId, instanceId] = storageKey.args @@ -145,7 +150,16 @@ export const useAccountOmnipoolPositions = (givenAddress?: string) => { } }) - return { omnipoolNfts, miningNfts } + const xykMiningNfts = xykMiningNftsRaw.map(([storageKey]) => { + const [owner, classId, instanceId] = storageKey.args + return { + owner: owner.toString(), + classId: classId.toString(), + instanceId: instanceId.toString(), + } + }) + + return { omnipoolNfts, miningNfts, xykMiningNfts } } : undefinedNoop, { enabled: !!address }, @@ -154,7 +168,7 @@ export const useAccountOmnipoolPositions = (givenAddress?: string) => { export const useAccountMiningPositions = () => { const { api } = useRpcProvider() - const { data } = useAccountOmnipoolPositions() + const { data } = useAccountNFTPositions() return useQueries({ queries: data?.miningNfts @@ -167,8 +181,38 @@ export const useAccountMiningPositions = () => { }) } +export const useAccountXYKMiningPositions = () => { + const { api } = useRpcProvider() + const { data } = useAccountNFTPositions() + + return useQueries({ + queries: data?.xykMiningNfts + ? data.xykMiningNfts.map((nft) => ({ + queryKey: QUERY_KEYS.miningPositionXYK(nft.instanceId), + queryFn: getMiningPositionXYK(api, nft.instanceId), + enabled: !!nft.instanceId, + })) + : [], + }) +} + const getMiningPosition = (api: ApiPromise, id: string) => async () => { - const dataRaw = await api.query.omnipoolWarehouseLM.deposit(id) + const key = api.query.omnipoolWarehouseLM.deposit.key(id) + + const value = (await api.rpc.state.getStorage( + key, + )) as Option + + const data = api.registry.createType( + "OmnipoolLMDeposit", + value.unwrap(), + ) as PalletLiquidityMiningDepositData + + return { id, data } +} + +const getMiningPositionXYK = (api: ApiPromise, id: string) => async () => { + const dataRaw = await api.query.xykWarehouseLM.deposit(id) const data = dataRaw.unwrap() return { id, data } @@ -575,11 +619,42 @@ export const useXYKPools = (withPositions?: boolean) => { export const useXYKPoolDetails = (pool: TXYKPool) => { const volume = useXYKPoolTradeVolumes([pool.poolAddress]) + const miningPositions = useAccountXYKMiningPositions() const isInitialLoading = volume.isLoading + const miningNftPositions = miningPositions + .filter( + (position) => + position.data?.data.ammPoolId.toString() === pool.poolAddress, + ) + .map((position) => position.data) + .filter(isNotNil) + .sort((a, b) => { + const firstFarmLastBlock = a.data.yieldFarmEntries.reduce( + (acc, curr) => + acc.lt(curr.enteredAt.toBigNumber()) + ? curr.enteredAt.toBigNumber() + : acc, + BN_0, + ) + + const secondFarmLastBlock = b.data.yieldFarmEntries.reduce( + (acc, curr) => + acc.lt(curr.enteredAt.toBigNumber()) + ? curr.enteredAt.toBigNumber() + : acc, + BN_0, + ) + + return secondFarmLastBlock.minus(firstFarmLastBlock).toNumber() + }) + return { - data: { volumeDisplay: volume.data?.[0]?.volume ?? BN_0 }, + data: { + volumeDisplay: volume.data?.[0]?.volume ?? BN_0, + miningNftPositions, + }, isInitialLoading, } } @@ -617,3 +692,65 @@ export const useXYKSpotPrice = (shareTokenId: string) => { return { priceA, priceB, idA: metaA.id, idB: metaB.id } } + +export const useDepositValues = ( + assetId: string, + depositNft: TMiningNftPosition, +) => { + const { assets } = useRpcProvider() + const totalIssuances = useShareOfPools([assetId]) + const meta = assets.getAsset(assetId) as TShareToken + + const balances = useTokensBalances(meta.assets, meta.poolAddress) + const shareTokeSpotPrices = useDisplayShareTokenPrice([assetId]) + + const data = useMemo(() => { + const defaultValue = { + assetA: undefined, + assetB: undefined, + amountUSD: undefined, + } + + if ( + !totalIssuances.data || + balances.some((balance) => !balance.data) || + !shareTokeSpotPrices.data + ) + return defaultValue + + const shareTokenIssuance = totalIssuances.data?.[0].totalShare + + if (!shareTokenIssuance) { + console.error("Could not calculate deposit balances") + return defaultValue + } + + const shares = depositNft.data.shares.toBigNumber() + const ratio = shares.div(shareTokenIssuance) + + const amountUSD = scaleHuman(shareTokenIssuance, meta.decimals) + .multipliedBy(shareTokeSpotPrices.data?.[0]?.spotPrice ?? 1) + .times(ratio) + + const [assetA, assetB] = meta.assets.map((asset) => { + const meta = assets.getAsset(asset) + const balance = + balances.find((balance) => balance.data?.assetId === asset)?.data + ?.balance ?? BN_0 + const amount = scaleHuman(balance.times(ratio), meta.decimals) + return { id: asset, symbol: meta.symbol, amount } + }) + + return { assetA, assetB, amountUSD } + }, [ + assets, + balances, + depositNft.data.shares, + meta.assets, + meta.decimals, + shareTokeSpotPrices.data, + totalIssuances.data, + ]) + + return data +} diff --git a/src/sections/pools/farms/FarmingPositionWrapper.tsx b/src/sections/pools/farms/FarmingPositionWrapper.tsx index 8bcf520ff..c2b26924f 100644 --- a/src/sections/pools/farms/FarmingPositionWrapper.tsx +++ b/src/sections/pools/farms/FarmingPositionWrapper.tsx @@ -5,7 +5,7 @@ import { Icon } from "components/Icon/Icon" import FPIcon from "assets/icons/PoolsAndFarms.svg?react" import { ClaimRewardsCard } from "./components/claimableCard/ClaimRewardsCard" import { Spacer } from "components/Spacer/Spacer" -import { TPool, TPoolDetails } from "sections/pools/PoolsPage.utils" +import { TPool, TPoolDetails, TXYKPool } from "sections/pools/PoolsPage.utils" import { Button } from "components/Button/Button" import ExitIcon from "assets/icons/Exit.svg?react" import { useFarmExitAllMutation } from "utils/farms/exit" @@ -14,7 +14,7 @@ import { ToastMessage } from "state/store" import { useAccount } from "sections/web3-connect/Web3Connect.utils" interface Props { - pool: TPool + pool: TPool | TXYKPool positions: TPoolDetails["miningNftPositions"] } @@ -32,7 +32,7 @@ export const FarmingPositionWrapper = ({ pool, positions }: Props) => { return memo }, {} as ToastMessage) - const exit = useFarmExitAllMutation(positions, toast) + const exit = useFarmExitAllMutation(positions, pool.id, toast) if (!positions.length) return null diff --git a/src/sections/pools/farms/modals/join/JoinFarmsButton.tsx b/src/sections/pools/farms/modals/join/JoinFarmsButton.tsx new file mode 100644 index 000000000..4028f8847 --- /dev/null +++ b/src/sections/pools/farms/modals/join/JoinFarmsButton.tsx @@ -0,0 +1,45 @@ +import { useFarms } from "api/farms" +import { Button } from "components/Button/Button" +import { Icon } from "components/Icon/Icon" +import { useState } from "react" +import { useTranslation } from "react-i18next" +import { useAccount } from "sections/web3-connect/Web3Connect.utils" +import FPIcon from "assets/icons/PoolsAndFarms.svg?react" +import { JoinFarmModal } from "sections/pools/farms/modals/join/JoinFarmsModal" +import { HydraPositionsTableData } from "sections/wallet/assets/hydraPositions/WalletAssetsHydraPositions.utils" + +export const JoinFarmsButton = (props: { + poolId: string + position?: HydraPositionsTableData + onSuccess: () => void +}) => { + const { t } = useTranslation() + const { account } = useAccount() + const [joinFarm, setJoinFarm] = useState(false) + const farms = useFarms([props.poolId]) + + return ( + <> + + + {joinFarm && farms.data && ( + setJoinFarm(false)} + onSuccess={props.onSuccess} + initialShares={props.position?.shares} + positionId={props.position?.id} + /> + )} + + ) +} diff --git a/src/sections/pools/farms/modals/join/JoinFarmsModal.tsx b/src/sections/pools/farms/modals/join/JoinFarmsModal.tsx index 22daa6a5f..d9f945d1f 100644 --- a/src/sections/pools/farms/modals/join/JoinFarmsModal.tsx +++ b/src/sections/pools/farms/modals/join/JoinFarmsModal.tsx @@ -9,8 +9,7 @@ import { Text } from "components/Typography/Text/Text" import { useState } from "react" import { useTranslation } from "react-i18next" import { TMiningNftPosition } from "sections/pools/PoolsPage.utils" -import { FarmDepositMutationType } from "utils/farms/deposit" -import { FarmRedepositMutationType } from "utils/farms/redeposit" +import { useFarmDepositMutation } from "utils/farms/deposit" import { FarmDetailsCard } from "sections/pools/farms/components/detailsCard/FarmDetailsCard" import { FarmDetailsModal } from "sections/pools/farms/modals/details/FarmDetailsModal" import { SJoinFarmContainer } from "./JoinFarmsModal.styled" @@ -22,25 +21,27 @@ import { scaleHuman } from "utils/balance" import { WalletTransferAssetSelect } from "sections/wallet/transfer/WalletTransferAssetSelect" import { useZodSchema } from "./JoinFarmsModal.utils" import { zodResolver } from "@hookform/resolvers/zod" +import { Spacer } from "components/Spacer/Spacer" +import { FormValues } from "utils/helpers" type JoinFarmModalProps = { - isOpen: boolean onClose: () => void + onSuccess: () => void poolId: string initialShares?: BigNumber + positionId?: string farms: Farm[] isRedeposit?: boolean - mutation?: FarmDepositMutationType | FarmRedepositMutationType depositNft?: TMiningNftPosition } export const JoinFarmModal = ({ - isOpen, onClose, + onSuccess, isRedeposit, poolId, - mutation, initialShares, + positionId, depositNft, farms, }: JoinFarmModalProps) => { @@ -55,6 +56,8 @@ export const JoinFarmModal = ({ const zodSchema = useZodSchema(meta.id, farms) + const mutation = useFarmDepositMutation(poolId, farms, onClose, onSuccess) + const form = useForm<{ amount: string }>({ mode: "onChange", defaultValues: { @@ -84,12 +87,14 @@ export const JoinFarmModal = ({ selectedFarm?.globalFarm.blocksPerPeriod.toNumber() ?? 1, ) - const onSubmit = () => mutation?.mutate() + const onSubmit = (values: FormValues) => { + mutation.mutate({ shares: values.amount, positionId: positionId ?? "" }) + } const error = form.formState.errors.amount?.message return ( - + - {mutation && ( -
- - {initialShares ? ( -
-
- {t("farms.modal.footer.title")} -
- - {t("value.token", { - value: initialShares, - fixedPointScale: meta.decimals, - })} - + + + + {initialShares ? ( +
+
+ {t("farms.modal.footer.title")}
- ) : ( + + {t("value.token", { + value: initialShares, + fixedPointScale: meta.decimals, + })} + +
+ ) : ( + <> + )} /> - )} + + + )} - {error && initialShares && ( - - {error} - - )} + {error && initialShares && ( + + {error} + + )} - -
- - )} + + + ), }, diff --git a/src/sections/pools/farms/modals/joinedFarmDetails/JoinedFarmsDetails.tsx b/src/sections/pools/farms/modals/joinedFarmDetails/JoinedFarmsDetails.tsx index 525ba642b..513358274 100644 --- a/src/sections/pools/farms/modals/joinedFarmDetails/JoinedFarmsDetails.tsx +++ b/src/sections/pools/farms/modals/joinedFarmDetails/JoinedFarmsDetails.tsx @@ -142,6 +142,7 @@ function JoinedFarmsDetailsPositions(props: { const exit = useFarmExitAllMutation( [props.depositNft], + props.poolId, toast, props.onTxClose, ) diff --git a/src/sections/pools/farms/position/FarmingPosition.tsx b/src/sections/pools/farms/position/FarmingPosition.tsx index 29d436673..02fe805c2 100644 --- a/src/sections/pools/farms/position/FarmingPosition.tsx +++ b/src/sections/pools/farms/position/FarmingPosition.tsx @@ -3,7 +3,10 @@ import { DollarAssetValue } from "components/DollarAssetValue/DollarAssetValue" import { Text } from "components/Typography/Text/Text" import { useState } from "react" import { Trans, useTranslation } from "react-i18next" -import { TMiningNftPosition } from "sections/pools/PoolsPage.utils" +import { + TMiningNftPosition, + useDepositValues, +} from "sections/pools/PoolsPage.utils" import { WalletAssetsHydraPositionsData } from "sections/wallet/assets/hydraPositions/data/WalletAssetsHydraPositionsData" import { useEnteredDate } from "utils/block" import { BN_0 } from "utils/constants" @@ -82,7 +85,7 @@ const ExitFarmsButton = (props: { return memo }, {} as ToastMessage) - const exit = useFarmExitAllMutation([props.depositNft], toast) + const exit = useFarmExitAllMutation([props.depositNft], props.poolId, toast) return (
+ + + + ) +} + +const OmnipoolFields = ({ + poolId, + depositNft, +}: { + poolId: string + depositNft: TMiningNftPosition +}) => { + const { t } = useTranslation() + const { assets } = useRpcProvider() + const position = useDepositShare(poolId, depositNft.id.toString()) + + const lpPosition = useOmnipoolPosition(position.data?.id) + const meta = lpPosition.data?.assetId + ? assets.getAsset(lpPosition.data.assetId.toString()) + : undefined + const spotPrice = useDisplayPrice(lpPosition.data?.assetId) + + const initialPosValue = + getFloatingPointAmount( + lpPosition.data?.amount.toBigNumber() ?? 0, + meta?.decimals ?? 12, + ) ?? BN_0 + + const initialPosPrice = initialPosValue.multipliedBy( + spotPrice.data?.spotPrice ?? 1, + ) + + return ( + <> + + + {t("farms.positions.labels.initialValue")} + +
+ + {t("value.tokenWithSymbol", { + value: initialPosValue, + symbol: meta?.symbol, + })} + + + + +
+
+ + +
- {t("farms.positions.labels.initialValue")} + {t("farms.positions.labels.currentValue")} + +
+ + {position.data && (
- - {t("value.tokenWithSymbol", { - value: initialPosValue, - symbol: meta?.symbol, - })} - - - - -
-
- - -
- - {t("farms.positions.labels.currentValue")} - - + ( + + {children} + + )} + > + +
+ )} +
+ + ) +} - {position.data && ( -
- - ( - - {children} - - )} - > - - -
- )} - -
+const XYKFields = ({ + poolId, + depositNft, +}: { + poolId: string + depositNft: TMiningNftPosition +}) => { + const { t } = useTranslation() + const { amountUSD, assetA, assetB } = useDepositValues(poolId, depositNft) - - + return ( + + + {t("farms.positions.labels.currentValue")} + +
+ + {t("value.tokenWithSymbol", { + value: assetA?.amount, + symbol: assetA?.symbol, + })}{" "} + |{" "} + {t("value.tokenWithSymbol", { + value: assetB?.amount, + symbol: assetB?.symbol, + })} + + + + +
+
) } diff --git a/src/sections/pools/farms/position/FarmingPosition.utils.tsx b/src/sections/pools/farms/position/FarmingPosition.utils.tsx index b8fbfcfc6..a7043a047 100644 --- a/src/sections/pools/farms/position/FarmingPosition.utils.tsx +++ b/src/sections/pools/farms/position/FarmingPosition.utils.tsx @@ -5,11 +5,7 @@ import { import { u32 } from "@polkadot/types" import { useTokensBalances } from "api/balances" import { useApiIds } from "api/consts" -import { - useAccountDepositIds, - useAllDeposits, - useOmniPositionIds, -} from "api/deposits" +import { useOmniPositionIds, useUserDeposits } from "api/deposits" import { OmnipoolPosition, useOmnipoolAssets, @@ -17,7 +13,6 @@ import { } from "api/omnipool" import BN from "bignumber.js" import { useMemo } from "react" -import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { OMNIPOOL_ACCOUNT_ADDRESS } from "utils/api" import { BN_10, BN_NAN } from "utils/constants" import { useDisplayPrice, useDisplayPrices } from "utils/displayAsset" @@ -30,18 +25,9 @@ export const useAllUserDepositShare = ({ address?: string } = {}) => { const { assets } = useRpcProvider() - const { account } = useAccount() - const accountDepositIds = useAccountDepositIds(address ?? account?.address) - const deposits = useAllDeposits() - - const ids = new Set( - accountDepositIds.data?.map((i) => i.instanceId.toString()), - ) + const { omnipoolDeposits } = useUserDeposits(address) - const depositIds = deposits.data?.reduce((memo, item) => { - if (ids.has(item.id.toString())) memo.push(item.id.toString()) - return memo - }, [] as Array) + const depositIds = omnipoolDeposits.map((deposit) => deposit.id) ?? [] const apiIds = useApiIds() const omnipoolAssets = useOmnipoolAssets() diff --git a/src/sections/pools/navigation/Navigation.tsx b/src/sections/pools/navigation/Navigation.tsx index 572965d9d..d6b21b692 100644 --- a/src/sections/pools/navigation/Navigation.tsx +++ b/src/sections/pools/navigation/Navigation.tsx @@ -5,7 +5,7 @@ import AllPools from "assets/icons/AllPools.svg?react" import OmniStablepools from "assets/icons/Omnipool&Stablepool.svg?react" import IsolatedPools from "assets/icons/IsolatedPools.svg?react" import { SSeparator } from "components/Separator/Separator.styled" -import { useAccountOmnipoolPositions } from "sections/pools/PoolsPage.utils" +import { useAccountNFTPositions } from "sections/pools/PoolsPage.utils" import { useRpcProvider } from "providers/rpcProvider" import { useTranslation } from "react-i18next" import { useTokensBalances } from "api/balances" @@ -55,7 +55,7 @@ const MyLiquidity = () => { const { t } = useTranslation() const { account } = useAccount() const { assets } = useRpcProvider() - const accountPositions = useAccountOmnipoolPositions() + const accountPositions = useAccountNFTPositions() const shareTokensId = assets.shareTokens.map((shareToken) => shareToken.id) const stableswapsId = assets.stableswap.map((shareToken) => shareToken.id) diff --git a/src/sections/pools/pool/Pool.tsx b/src/sections/pools/pool/Pool.tsx index 0095a17c8..03192e0d7 100644 --- a/src/sections/pools/pool/Pool.tsx +++ b/src/sections/pools/pool/Pool.tsx @@ -42,7 +42,8 @@ const XYKPool = ({ pool }: { pool: TXYKPool }) => { return ( - + + ) } diff --git a/src/sections/pools/pool/availableFarms/AvailableFarms.tsx b/src/sections/pools/pool/availableFarms/AvailableFarms.tsx index f14753ba2..2cd7ee371 100644 --- a/src/sections/pools/pool/availableFarms/AvailableFarms.tsx +++ b/src/sections/pools/pool/availableFarms/AvailableFarms.tsx @@ -1,5 +1,5 @@ import { useTranslation } from "react-i18next" -import { TPool } from "sections/pools/PoolsPage.utils" +import { TPool, TXYKPool } from "sections/pools/PoolsPage.utils" import { useFarms } from "api/farms" import { FarmDetailsCard } from "sections/pools/farms/components/detailsCard/FarmDetailsCard" import { useState } from "react" @@ -9,7 +9,7 @@ import { FarmDetailsModal } from "sections/pools/farms/modals/details/FarmDetail import { useBestNumber } from "api/chain" import { Text } from "components/Typography/Text/Text" -export const AvailableFarms = ({ pool }: { pool: TPool }) => { +export const AvailableFarms = ({ pool }: { pool: TPool | TXYKPool }) => { const { t } = useTranslation() const [selectedFarmId, setSelectedFarmId] = useState<{ yieldFarmId: u32 diff --git a/src/sections/pools/pool/myPositions/MyPositions.tsx b/src/sections/pools/pool/myPositions/MyPositions.tsx index 48038145c..20d737ff4 100644 --- a/src/sections/pools/pool/myPositions/MyPositions.tsx +++ b/src/sections/pools/pool/myPositions/MyPositions.tsx @@ -5,7 +5,7 @@ import { Text } from "components/Typography/Text/Text" import { useRpcProvider } from "providers/rpcProvider" import { useMemo } from "react" import { useTranslation } from "react-i18next" -import { TPoolFullData, TXYKPool } from "sections/pools/PoolsPage.utils" +import { TPoolFullData, TXYKPoolFullData } from "sections/pools/PoolsPage.utils" import { FarmingPositionWrapper } from "sections/pools/farms/FarmingPositionWrapper" import { useAllUserDepositShare } from "sections/pools/farms/position/FarmingPosition.utils" import { LiquidityPositionWrapper } from "sections/pools/pool/positions/LiquidityPositionWrapper" @@ -125,6 +125,11 @@ export const MyPositions = ({ pool }: { pool: TPoolFullData }) => { ) } -export const MyXYKPositions = ({ pool }: { pool: TXYKPool }) => { - return +export const MyXYKPositions = ({ pool }: { pool: TXYKPoolFullData }) => { + return ( +
+ + +
+ ) } diff --git a/src/sections/pools/pool/positions/LiquidityPosition.tsx b/src/sections/pools/pool/positions/LiquidityPosition.tsx index c6c769182..96f4c3de0 100644 --- a/src/sections/pools/pool/positions/LiquidityPosition.tsx +++ b/src/sections/pools/pool/positions/LiquidityPosition.tsx @@ -3,7 +3,7 @@ import { Icon } from "components/Icon/Icon" import { Separator } from "components/Separator/Separator" import { Text } from "components/Typography/Text/Text" import TrashIcon from "assets/icons/IconRemove.svg?react" -import { Trans, useTranslation } from "react-i18next" +import { useTranslation } from "react-i18next" import { SContainer } from "sections/pools/pool/positions/LiquidityPosition.styled" import { HydraPositionsTableData } from "sections/wallet/assets/hydraPositions/WalletAssetsHydraPositions.utils" import { WalletAssetsHydraPositionsData } from "sections/wallet/assets/hydraPositions/data/WalletAssetsHydraPositionsData" @@ -11,12 +11,6 @@ import { DollarAssetValue } from "components/DollarAssetValue/DollarAssetValue" import { useState } from "react" import { RemoveLiquidity } from "sections/pools/modals/RemoveLiquidity/RemoveLiquidity" import { Button } from "components/Button/Button" -import FPIcon from "assets/icons/PoolsAndFarms.svg?react" -import { JoinFarmModal } from "sections/pools/farms/modals/join/JoinFarmsModal" -import { useFarms } from "api/farms" -import { useFarmDepositMutation } from "utils/farms/deposit" -import { TOAST_MESSAGES } from "state/toasts" -import { ToastMessage } from "state/store" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { DisplayValue } from "components/DisplayValue/DisplayValue" import { LrnaPositionTooltip } from "sections/pools/components/LrnaPositionTooltip" @@ -25,6 +19,7 @@ import { MultipleIcons } from "components/MultipleIcons/MultipleIcons" import { TPoolFullData, TXYKPool } from "sections/pools/PoolsPage.utils" import { useMedia } from "react-use" import { theme } from "theme" +import { JoinFarmsButton } from "sections/pools/farms/modals/join/JoinFarmsButton" type Props = { position: HydraPositionsTableData @@ -33,71 +28,6 @@ type Props = { onSuccess: () => void } -function LiquidityPositionJoinFarmButton(props: { - poolId: string - position: HydraPositionsTableData - onSuccess: () => void -}) { - const { t } = useTranslation() - const { assets } = useRpcProvider() - const { account } = useAccount() - const [joinFarm, setJoinFarm] = useState(false) - const farms = useFarms([props.poolId]) - const meta = assets.getAsset(props.poolId.toString()) - - const toast = TOAST_MESSAGES.reduce((memo, type) => { - const msType = type === "onError" ? "onLoading" : type - memo[type] = ( - - - - - ) - return memo - }, {} as ToastMessage) - - const joinFarmMutation = useFarmDepositMutation( - props.poolId, - props.position.id, - toast, - () => setJoinFarm(false), - props.onSuccess, - ) - - return ( - <> - - - {joinFarm && farms.data && ( - setJoinFarm(false)} - mutation={joinFarmMutation} - /> - )} - - ) -} - export function LiquidityPositionRemoveLiquidity( props: | { @@ -178,7 +108,7 @@ export const LiquidityPosition = ({ }} > {!meta.isStableSwap && ( - void -}) => { - const { t } = useTranslation() - const { assets } = useRpcProvider() - const { account } = useAccount() - const [joinFarm, setJoinFarm] = useState(false) - const farms = useFarms([props.poolId]) - const meta = assets.getAsset(props.poolId.toString()) - - const toast = TOAST_MESSAGES.reduce((memo, type) => { - const msType = type === "onError" ? "onLoading" : type - memo[type] = ( - - - - - ) - return memo - }, {} as ToastMessage) - - const joinFarmMutation = useFarmDepositMutation( - props.poolId, - positionId, - toast, - () => setJoinFarm(false), - props.onSuccess, - ) - - return ( - <> - - - {joinFarm && farms.data && ( - setJoinFarm(false)} - mutation={joinFarmMutation} - /> - )} - - ) -} diff --git a/src/sections/pools/pool/xykPosition/XYKPosition.tsx b/src/sections/pools/pool/xykPosition/XYKPosition.tsx index 8854915c7..25512027d 100644 --- a/src/sections/pools/pool/xykPosition/XYKPosition.tsx +++ b/src/sections/pools/pool/xykPosition/XYKPosition.tsx @@ -18,7 +18,7 @@ import { LiquidityPositionRemoveLiquidity } from "sections/pools/pool/positions/ import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { useMedia } from "react-use" import { theme } from "theme" -import { JoinFarmsButton } from "./JoinFarmsButton" +import { JoinFarmsButton } from "sections/pools/farms/modals/join/JoinFarmsButton" export const XYKPosition = ({ pool }: { pool: TXYKPool }) => { const { t } = useTranslation() @@ -79,7 +79,7 @@ export const XYKPosition = ({ pool }: { pool: TXYKPool }) => { return null return ( -
+
{t("liquidity.pool.positions.title")} diff --git a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx index 89b1e79c6..b09688d08 100644 --- a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx +++ b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx @@ -7,7 +7,7 @@ import { VisibilityState, } from "@tanstack/react-table" import { useBestNumber } from "api/chain" -import { useAccountDepositIds, useAllDeposits } from "api/deposits" +import { useUserDeposits } from "api/deposits" import BN from "bignumber.js" import { DollarAssetValue } from "components/DollarAssetValue/DollarAssetValue" import { Text } from "components/Typography/Text/Text" @@ -16,7 +16,6 @@ import { useMemo, useState } from "react" import { useTranslation } from "react-i18next" import { useMedia } from "react-use" import { useAllUserDepositShare } from "sections/pools/farms/position/FarmingPosition.utils" -import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { theme } from "theme" import { getFloatingPointAmount } from "utils/balance" import { getEnteredDate } from "utils/block" @@ -150,37 +149,18 @@ export const useFarmingPositionsData = ({ search?: string } = {}) => { const { assets } = useRpcProvider() - const { account } = useAccount() - const allDeposits = useAllDeposits() - const accountDepositIds = useAccountDepositIds(account?.address) + const { omnipoolDeposits } = useUserDeposits() const accountDepositsShare = useAllUserDepositShare() - const accountDeposits = useMemo( - () => - allDeposits.data?.filter( - (deposit) => - accountDepositIds.data?.some( - (d) => d.instanceId.toString() === deposit.id.toString(), - ), - ), - [allDeposits.data, accountDepositIds.data], - ) - const bestNumber = useBestNumber() - const queries = [ - allDeposits, - accountDepositIds, - accountDepositsShare, - bestNumber, - ] + const queries = [accountDepositsShare, bestNumber] const isLoading = queries.some((q) => q.isLoading) const data = useMemo(() => { - if (!accountDeposits || !accountDepositsShare.data || !bestNumber.data) - return [] + if (!accountDepositsShare.data || !bestNumber.data) return [] - const rows: FarmingPositionsTableData[] = accountDeposits + const rows: FarmingPositionsTableData[] = omnipoolDeposits .map((deposit) => { const id = deposit.id.toString() const assetId = deposit.data.ammPoolId.toString() @@ -231,11 +211,11 @@ export const useFarmingPositionsData = ({ return search ? arraySearch(rows, search, ["symbol", "name"]) : rows }, [ - search, - accountDeposits, accountDepositsShare.data, - assets, bestNumber.data, + omnipoolDeposits, + search, + assets, ]) return { data, isLoading } diff --git a/src/sections/wallet/assets/hydraPositions/data/WalletAssetsHydraPositionsData.utils.tsx b/src/sections/wallet/assets/hydraPositions/data/WalletAssetsHydraPositionsData.utils.tsx index b06b52275..77e1e89e1 100644 --- a/src/sections/wallet/assets/hydraPositions/data/WalletAssetsHydraPositionsData.utils.tsx +++ b/src/sections/wallet/assets/hydraPositions/data/WalletAssetsHydraPositionsData.utils.tsx @@ -8,7 +8,7 @@ import { useDisplayPrices } from "utils/displayAsset" import { arraySearch, isNotNil } from "utils/helpers" import { useRpcProvider } from "providers/rpcProvider" import { calculatePositionLiquidity } from "utils/omnipool" -import { useAccountOmnipoolPositions } from "sections/pools/PoolsPage.utils" +import { useAccountNFTPositions } from "sections/pools/PoolsPage.utils" import { useShareTokens } from "api/xyk" import { useAccountsBalances } from "api/accountBalances" import { useShareOfPools } from "api/pools" @@ -21,7 +21,7 @@ export const useOmnipoolPositionsData = ({ address, }: { search?: string; address?: string } = {}) => { const { assets } = useRpcProvider() - const accountPositions = useAccountOmnipoolPositions(address) + const accountPositions = useAccountNFTPositions(address) const positions = useOmnipoolPositions( accountPositions.data?.omnipoolNfts.map((nft) => nft.instanceId) ?? [], ) diff --git a/src/utils/farms/claiming.ts b/src/utils/farms/claiming.ts index b44ff6d58..ec9c42141 100644 --- a/src/utils/farms/claiming.ts +++ b/src/utils/farms/claiming.ts @@ -1,8 +1,5 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions */ import { u32 } from "@polkadot/types" import { AccountId32 } from "@polkadot/types/interfaces" -import { u8aToHex } from "@polkadot/util" -import { decodeAddress } from "@polkadot/util-crypto" import { useMutation } from "@tanstack/react-query" import { useAccountAssetBalances } from "api/accountBalances" import { useBestNumber } from "api/chain" @@ -27,24 +24,33 @@ export const useClaimableAmount = ( depositNft?: TMiningNftPosition, ) => { const bestNumberQuery = useBestNumber() + const { api, assets } = useRpcProvider() + const { omnipoolDeposits, xykDeposits } = useUserDeposits() - const allDeposits = useUserDeposits() + const meta = poolId ? assets.getAsset(poolId) : undefined + const isXYK = assets.isShareToken(meta) - const filteredDeposits = poolId - ? { - ...allDeposits, - data: - allDeposits.data?.filter( - (deposit) => deposit.data.ammPoolId.toString() === poolId, - ) ?? [], - } - : allDeposits + const filteredDeposits = useMemo( + () => + poolId + ? [...omnipoolDeposits, ...xykDeposits].filter((deposit) => { + return ( + deposit.data.ammPoolId.toString() === + (isXYK ? meta.poolAddress : poolId) + ) + }) ?? [] + : [...omnipoolDeposits, ...xykDeposits], + [isXYK, meta, omnipoolDeposits, poolId, xykDeposits], + ) const omnipoolAssets = useOmnipoolAssets() const poolIds = poolId ? [poolId] - : omnipoolAssets.data?.map((asset) => asset.id.toString()) ?? [] + : [ + ...(omnipoolAssets.data?.map((asset) => asset.id.toString()) ?? []), + ...assets.shareTokens.map((asset) => asset.id), + ] const farms = useFarms(poolIds) @@ -55,7 +61,6 @@ export const useClaimableAmount = ( [farms.data, inactiveFarms.data], ) - const { api, assets } = useRpcProvider() const accountResolver = getAccountResolver(api.registry) const assetIds = [ @@ -89,7 +94,6 @@ export const useClaimableAmount = ( const queries = [ bestNumberQuery, - filteredDeposits, farms, inactiveFarms, accountBalances, @@ -100,14 +104,13 @@ export const useClaimableAmount = ( const data = useMemo(() => { if ( !bestNumberQuery.data || - !filteredDeposits.data || + !filteredDeposits.length || !accountBalances.data || !spotPrices.data ) return undefined - const deposits = - depositNft != null ? [depositNft] : filteredDeposits.data ?? [] + const deposits = depositNft != null ? [depositNft] : filteredDeposits ?? [] const bestNumber = bestNumberQuery const multiCurrency = new MultiCurrencyContainer( @@ -148,7 +151,8 @@ export const useClaimableAmount = ( yieldFarms[aprEntry.yieldFarm.id.toString()], farmEntry, bestNumber.data.relaychainBlockNumber.toBigNumber(), - oracle.data.oraclePrice, + oracle.data.oraclePrice ?? + aprEntry.globalFarm.priceAdjustment.toBigNumber(), ) const spotPrice = spotPrices.data?.find( @@ -207,7 +211,7 @@ export const useClaimableAmount = ( bestNumberQuery, depositNft, allFarms, - filteredDeposits.data, + filteredDeposits, metas, oraclePrices, spotPrices.data, @@ -226,13 +230,14 @@ export const useClaimAllMutation = ( const { api } = useRpcProvider() const { createTransaction } = useStore() - const allUserDeposits = useUserDeposits() + //TODO: ADD xykDeposits as well + const { omnipoolDeposits } = useUserDeposits() const filteredDeposits = poolId - ? allUserDeposits.data?.filter( + ? omnipoolDeposits.filter( (deposit) => deposit.data.ammPoolId.toString() === poolId.toString(), ) ?? [] - : allUserDeposits.data + : omnipoolDeposits const deposits = depositNft ? [depositNft] : filteredDeposits @@ -257,6 +262,3 @@ export const useClaimAllMutation = ( } }) } - -// @ts-expect-error -window.decodeAddressToBytes = (bsx: string) => u8aToHex(decodeAddress(bsx)) diff --git a/src/utils/farms/deposit.ts b/src/utils/farms/deposit.tsx similarity index 51% rename from src/utils/farms/deposit.ts rename to src/utils/farms/deposit.tsx index a0a74f4cc..623ebb5f6 100644 --- a/src/utils/farms/deposit.ts +++ b/src/utils/farms/deposit.tsx @@ -1,29 +1,49 @@ import { useMutation } from "@tanstack/react-query" -import { useFarms } from "api/farms" +import { Farm } from "api/farms" import { StepProps } from "components/Stepper/Stepper" -import { useTranslation } from "react-i18next" +import { Trans, useTranslation } from "react-i18next" import { ToastMessage, useStore } from "state/store" import { useRpcProvider } from "providers/rpcProvider" +import { TOAST_MESSAGES } from "state/toasts" +import { scale } from "utils/balance" export type FarmDepositMutationType = ReturnType export const useFarmDepositMutation = ( poolId: string, - positionId: string, - toast: ToastMessage, + farms: Farm[], onClose: () => void, onSuccess: () => void, ) => { const { createTransaction } = useStore() - const { api } = useRpcProvider() - const farms = useFarms([poolId]) + const { api, assets } = useRpcProvider() const { t } = useTranslation() + const meta = assets.getAsset(poolId) + const isXYK = assets.isShareToken(meta) + return useMutation( - async () => { - const [firstFarm, ...restFarm] = farms.data ?? [] + async ({ shares, positionId }: { shares: string; positionId: string }) => { + const [firstFarm, ...restFarm] = farms ?? [] if (firstFarm == null) throw new Error("Missing farm") + const toast = TOAST_MESSAGES.reduce((memo, type) => { + const msType = type === "onError" ? "onLoading" : type + memo[type] = ( + + + + + ) + return memo + }, {} as ToastMessage) + const firstStep: StepProps[] = [ { label: t("farms.modal.join.step", { number: 1 }), @@ -37,11 +57,18 @@ export const useFarmDepositMutation = ( const firstDeposit = await createTransaction( { - tx: api.tx.omnipoolLiquidityMining.depositShares( - firstFarm.globalFarm.id, - firstFarm.yieldFarm.id, - positionId, - ), + tx: isXYK + ? api.tx.xykLiquidityMining.depositShares( + firstFarm.globalFarm.id, + firstFarm.yieldFarm.id, + { assetIn: meta.assets[0], assetOut: meta.assets[1] }, + scale(shares, meta.decimals).toString(), + ) + : api.tx.omnipoolLiquidityMining.depositShares( + firstFarm.globalFarm.id, + firstFarm.yieldFarm.id, + positionId, + ), }, { toast, @@ -70,11 +97,18 @@ export const useFarmDepositMutation = ( ] const txs = restFarm.map((farm) => - api.tx.omnipoolLiquidityMining.redepositShares( - farm.globalFarm.id, - farm.yieldFarm.id, - depositId, - ), + isXYK + ? api.tx.xykLiquidityMining.redepositShares( + firstFarm.globalFarm.id, + firstFarm.yieldFarm.id, + { assetIn: meta.assets[0], assetOut: meta.assets[1] }, + depositId, + ) + : api.tx.omnipoolLiquidityMining.redepositShares( + farm.globalFarm.id, + farm.yieldFarm.id, + depositId, + ), ) if (txs.length > 0) { diff --git a/src/utils/farms/exit.ts b/src/utils/farms/exit.ts index 838190619..1a3966871 100644 --- a/src/utils/farms/exit.ts +++ b/src/utils/farms/exit.ts @@ -7,24 +7,34 @@ import { QUERY_KEYS } from "utils/queryKeys" export const useFarmExitAllMutation = ( depositNfts: TMiningNftPosition[], + poolId: string, toast: ToastMessage, onClose?: () => void, ) => { - const { api } = useRpcProvider() + const { api, assets } = useRpcProvider() const { createTransaction } = useStore() const { account } = useAccount() const queryClient = useQueryClient() + const meta = assets.getAsset(poolId) + const isXYK = assets.isShareToken(meta) + return useMutation( async () => { const txs = depositNfts ?.map((record) => { return record.data.yieldFarmEntries.map((entry) => { - return api.tx.omnipoolLiquidityMining.withdrawShares( - record.id, - entry.yieldFarmId, - ) + return isXYK + ? api.tx.xykLiquidityMining.withdrawShares( + record.id, + entry.yieldFarmId, + { assetIn: meta.assets[0], assetOut: meta.assets[1] }, + ) + : api.tx.omnipoolLiquidityMining.withdrawShares( + record.id, + entry.yieldFarmId, + ) }) }) .flat(2) ?? [] diff --git a/src/utils/queryKeys.ts b/src/utils/queryKeys.ts index 194f33124..6f87a39cb 100644 --- a/src/utils/queryKeys.ts +++ b/src/utils/queryKeys.ts @@ -28,6 +28,7 @@ export const QUERY_KEYS = { id?.toString(), ], miningPosition: (id: string) => ["miningPosition", id], + miningPositionXYK: (id: string) => ["miningPositionXYK", id], accountBalances: (id: Maybe) => [ QUERY_KEY_PREFIX, "accountBalances", @@ -57,45 +58,34 @@ export const QUERY_KEYS = { address.toString(), ], deposit: (id: Maybe) => [QUERY_KEY_PREFIX, "deposit", id?.toString()], - allDeposits: [QUERY_KEY_PREFIX, "deposits"], - poolDeposits: (poolId: Maybe) => [ + allXYKDeposits: [QUERY_KEY_PREFIX, "allXYKDeposits"], + omnipoolDeposits: (ids: string[]) => [ QUERY_KEY_PREFIX, - "deposits", - poolId?.toString(), + "omnipoolDeposits", + ids.join("."), ], - accountDepositIds: (accountId: Maybe) => [ + xykDeposits: (ids: string[]) => [ QUERY_KEY_PREFIX, - "depositIds", - accountId?.toString(), + "xykDeposits", + ids.join("."), ], - globalFarms: (ids: Maybe<{ globalFarmId: u32 }[]>) => [ + poolDeposits: (poolId: Maybe) => [ QUERY_KEY_PREFIX, - "globalFarms", - ids?.map((i) => i.globalFarmId.toString()), + "deposits", + poolId?.toString(), ], - yieldFarms: ( - ids: Maybe< - { - poolId: u32 | string - globalFarmId: u32 | string - yieldFarmId: u32 | string - }[] - >, - ) => [QUERY_KEY_PREFIX, "yieldFarms", ids], activeYieldFarms: (poolId: Maybe) => [ "activeYieldFarms", poolId?.toString(), ], - globalFarm: (id: Maybe) => [ - QUERY_KEY_PREFIX, - "globalFarm", - id?.toString(), + activeYieldFarmsXYK: (poolId: Maybe) => [ + "activeYieldFarmsXYK", + poolId?.toString(), ], - yieldFarm: (ids: { - poolId: Maybe - globalFarmId: Maybe - yieldFarmId: Maybe - }) => [QUERY_KEY_PREFIX, "yieldFarm", ids], + globalFarm: (id: string) => [QUERY_KEY_PREFIX, "globalFarm", id.toString], + globalFarmXYK: (id: string) => [QUERY_KEY_PREFIX, "globalFarmXYK", id], + yieldFarm: (id: string) => [QUERY_KEY_PREFIX, "yieldFarm", id], + yieldFarmXYK: (id: string) => [QUERY_KEY_PREFIX, "yieldFarmXYK", id], activeYieldFarm: (id: string) => [QUERY_KEY_PREFIX, "activeYieldFarm", id], totalLiquidity: (id: Maybe) => [ QUERY_KEY_PREFIX, From f8c8301aa719d508ada473ed0a21a0931a4d24b0 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Sat, 13 Apr 2024 12:45:56 +0200 Subject: [PATCH 014/103] Fix omnipool farms --- src/api/deposits.ts | 112 +++++------------- src/api/provider.ts | 13 ++ src/sections/pools/PoolsPage.utils.ts | 16 ++- .../farms/position/FarmingPosition.utils.tsx | 20 +--- .../WalletFarmingPositions.utils.tsx | 38 +----- src/utils/farms/claiming.ts | 22 ++-- src/utils/queryKeys.ts | 5 + 7 files changed, 81 insertions(+), 145 deletions(-) diff --git a/src/api/deposits.ts b/src/api/deposits.ts index e1609d872..dc957bccb 100644 --- a/src/api/deposits.ts +++ b/src/api/deposits.ts @@ -1,52 +1,16 @@ import { ApiPromise } from "@polkadot/api" -import { u128, u32 } from "@polkadot/types" -import { AccountId32 } from "@polkadot/types/interfaces" +import { u128, u32, Option } from "@polkadot/types" import { useQueries, useQuery } from "@tanstack/react-query" -import { useAccount } from "sections/web3-connect/Web3Connect.utils" -import { Maybe, undefinedNoop, useQueryReduce } from "utils/helpers" import { QUERY_KEYS } from "utils/queryKeys" import { useRpcProvider } from "providers/rpcProvider" +import { PalletLiquidityMiningDepositData } from "@polkadot/types/lookup" +import { useAccountOmnipoolPositions } from "sections/pools/PoolsPage.utils" -const DEPOSIT_NFT_COLLECTION_ID = "2584" - -export const useAccountDepositIds = ( - accountId: Maybe, -) => { +export const useOmnipoolDeposits = (ids: string[]) => { const { api } = useRpcProvider() - return useQuery( - QUERY_KEYS.accountDepositIds(accountId), - accountId != null ? getAccountDepositIds(api, accountId) : undefinedNoop, - { enabled: !!accountId }, - ) -} - -const getAccountDepositIds = - (api: ApiPromise, accountId: AccountId32 | string) => async () => { - const res = await api.query.uniques.account.entries( - accountId, - DEPOSIT_NFT_COLLECTION_ID, - ) - const nfts = res.map(([storageKey]) => { - const [owner, classId, instanceId] = storageKey.args - return { owner, classId, instanceId } - }) - - return nfts - } -export const useAllDeposits = () => { - const { api } = useRpcProvider() - return useQuery(QUERY_KEYS.allDeposits, getDeposits(api)) -} - -export const usePoolDeposits = (poolId?: u32 | string) => { - const { api } = useRpcProvider() - return useQuery(QUERY_KEYS.poolDeposits(poolId), getDeposits(api), { - enabled: !!poolId, - select: (data) => - data.filter( - (item) => item.data.ammPoolId.toString() === poolId?.toString(), - ), + return useQuery(QUERY_KEYS.omnipoolDeposits(ids), getDeposits(api, ids), { + enabled: !!ids.length, }) } @@ -71,12 +35,25 @@ export const useOmniPositionIds = (positionIds: Array) => { }) } -const getDeposits = (api: ApiPromise) => async () => { - const res = await api.query.omnipoolWarehouseLM.deposit.entries() - return res.map(([key, value]) => ({ - id: key.args[0], - data: value.unwrap(), - })) +const getDeposits = (api: ApiPromise, ids: string[]) => async () => { + if (!ids.length) return undefined + + const keys = ids.map((id) => api.query.omnipoolWarehouseLM.deposit.key(id)) + const values = (await api.rpc.state.queryStorageAt( + keys, + )) as Option[] + + const data = values + .filter((value) => !value.isNone) + .map( + (value) => + api.registry.createType( + "OmnipoolLMDeposit", + value.unwrap(), + ) as PalletLiquidityMiningDepositData, + ) + + return ids.map((id, i) => ({ id, data: data[i] })) } const getOmniPositionId = @@ -86,38 +63,13 @@ const getOmniPositionId = return { depositionId, value: res.value } } -export const useAccountDeposits = (poolId?: u32) => { - const { account } = useAccount() - const accountDepositIds = useAccountDepositIds(account?.address) - const deposits = usePoolDeposits(poolId) +export const useUserDeposits = (address?: string) => { + const nftPositions = useAccountOmnipoolPositions(address) - return useQueryReduce( - [accountDepositIds, deposits] as const, - (accountDepositIds, deposits) => { - const ids = new Set( - accountDepositIds?.map((i) => i.instanceId.toString()), - ) - return deposits.filter((item) => ids.has(item.id.toString())) - }, - ) -} - -export const useUserDeposits = () => { - const { account } = useAccount() - const accountDepositIds = useAccountDepositIds(account?.address) - const deposits = useAllDeposits() - - const query = useQueryReduce( - [accountDepositIds, deposits] as const, - (accountDepositIds, deposits) => { - return deposits.filter( - (deposit) => - accountDepositIds?.some( - (id) => id.instanceId.toString() === deposit.id.toString(), - ), - ) - }, - ) + const { miningNfts = [] } = nftPositions.data ?? {} + const omnipoolDeposits = + useOmnipoolDeposits(miningNfts.map((miningNft) => miningNft.instanceId)) + .data ?? [] - return query + return omnipoolDeposits } diff --git a/src/api/provider.ts b/src/api/provider.ts index 37fa9242c..6aba664c5 100644 --- a/src/api/provider.ts +++ b/src/api/provider.ts @@ -102,6 +102,19 @@ export const useProviderData = (rpcUrl: string) => { const apiPool = SubstrateApis.getInstance() const api = await apiPool.api(url) + api.registry.register({ + XykLMDeposit: { + shares: "u128", + ammPoolId: "AccountId", + yieldFarmEntries: "Vec", + }, + OmnipoolLMDeposit: { + shares: "u128", + ammPoolId: "u32", + yieldFarmEntries: "Vec", + }, + }) + const { isStableCoin, stableCoinId: chainStableCoinId, diff --git a/src/sections/pools/PoolsPage.utils.ts b/src/sections/pools/PoolsPage.utils.ts index 6810831b3..950125c67 100644 --- a/src/sections/pools/PoolsPage.utils.ts +++ b/src/sections/pools/PoolsPage.utils.ts @@ -42,6 +42,8 @@ import { is_remove_liquidity_allowed, is_sell_allowed, } from "@galacticcouncil/math-omnipool" +import { Option } from "@polkadot/types" +import { PalletLiquidityMiningDepositData } from "@polkadot/types/lookup" export const useAssetsTradability = () => { const { @@ -168,8 +170,18 @@ export const useAccountMiningPositions = () => { } const getMiningPosition = (api: ApiPromise, id: string) => async () => { - const dataRaw = await api.query.omnipoolWarehouseLM.deposit(id) - const data = dataRaw.unwrap() + const key = api.query.omnipoolWarehouseLM.deposit.key(id) + + const value = (await api.rpc.state.getStorage( + key, + )) as Option + + if (value.isNone) return undefined + + const data = api.registry.createType( + "OmnipoolLMDeposit", + value.unwrap(), + ) as PalletLiquidityMiningDepositData return { id, data } } diff --git a/src/sections/pools/farms/position/FarmingPosition.utils.tsx b/src/sections/pools/farms/position/FarmingPosition.utils.tsx index b8fbfcfc6..f6db32994 100644 --- a/src/sections/pools/farms/position/FarmingPosition.utils.tsx +++ b/src/sections/pools/farms/position/FarmingPosition.utils.tsx @@ -5,11 +5,7 @@ import { import { u32 } from "@polkadot/types" import { useTokensBalances } from "api/balances" import { useApiIds } from "api/consts" -import { - useAccountDepositIds, - useAllDeposits, - useOmniPositionIds, -} from "api/deposits" +import { useOmniPositionIds, useUserDeposits } from "api/deposits" import { OmnipoolPosition, useOmnipoolAssets, @@ -17,7 +13,6 @@ import { } from "api/omnipool" import BN from "bignumber.js" import { useMemo } from "react" -import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { OMNIPOOL_ACCOUNT_ADDRESS } from "utils/api" import { BN_10, BN_NAN } from "utils/constants" import { useDisplayPrice, useDisplayPrices } from "utils/displayAsset" @@ -30,18 +25,9 @@ export const useAllUserDepositShare = ({ address?: string } = {}) => { const { assets } = useRpcProvider() - const { account } = useAccount() - const accountDepositIds = useAccountDepositIds(address ?? account?.address) - const deposits = useAllDeposits() - - const ids = new Set( - accountDepositIds.data?.map((i) => i.instanceId.toString()), - ) + const deposits = useUserDeposits(address) - const depositIds = deposits.data?.reduce((memo, item) => { - if (ids.has(item.id.toString())) memo.push(item.id.toString()) - return memo - }, [] as Array) + const depositIds = deposits.map((deposit) => deposit.id) ?? [] const apiIds = useApiIds() const omnipoolAssets = useOmnipoolAssets() diff --git a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx index 89b1e79c6..5d67259bf 100644 --- a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx +++ b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx @@ -7,7 +7,7 @@ import { VisibilityState, } from "@tanstack/react-table" import { useBestNumber } from "api/chain" -import { useAccountDepositIds, useAllDeposits } from "api/deposits" +import { useUserDeposits } from "api/deposits" import BN from "bignumber.js" import { DollarAssetValue } from "components/DollarAssetValue/DollarAssetValue" import { Text } from "components/Typography/Text/Text" @@ -16,7 +16,6 @@ import { useMemo, useState } from "react" import { useTranslation } from "react-i18next" import { useMedia } from "react-use" import { useAllUserDepositShare } from "sections/pools/farms/position/FarmingPosition.utils" -import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { theme } from "theme" import { getFloatingPointAmount } from "utils/balance" import { getEnteredDate } from "utils/block" @@ -150,37 +149,18 @@ export const useFarmingPositionsData = ({ search?: string } = {}) => { const { assets } = useRpcProvider() - const { account } = useAccount() - const allDeposits = useAllDeposits() - const accountDepositIds = useAccountDepositIds(account?.address) + const deposits = useUserDeposits() const accountDepositsShare = useAllUserDepositShare() - const accountDeposits = useMemo( - () => - allDeposits.data?.filter( - (deposit) => - accountDepositIds.data?.some( - (d) => d.instanceId.toString() === deposit.id.toString(), - ), - ), - [allDeposits.data, accountDepositIds.data], - ) - const bestNumber = useBestNumber() - const queries = [ - allDeposits, - accountDepositIds, - accountDepositsShare, - bestNumber, - ] + const queries = [accountDepositsShare, bestNumber] const isLoading = queries.some((q) => q.isLoading) const data = useMemo(() => { - if (!accountDeposits || !accountDepositsShare.data || !bestNumber.data) - return [] + if (!deposits || !accountDepositsShare.data || !bestNumber.data) return [] - const rows: FarmingPositionsTableData[] = accountDeposits + const rows: FarmingPositionsTableData[] = deposits .map((deposit) => { const id = deposit.id.toString() const assetId = deposit.data.ammPoolId.toString() @@ -230,13 +210,7 @@ export const useFarmingPositionsData = ({ ) return search ? arraySearch(rows, search, ["symbol", "name"]) : rows - }, [ - search, - accountDeposits, - accountDepositsShare.data, - assets, - bestNumber.data, - ]) + }, [search, accountDepositsShare.data, assets, bestNumber.data, deposits]) return { data, isLoading } } diff --git a/src/utils/farms/claiming.ts b/src/utils/farms/claiming.ts index b44ff6d58..8d574a4c0 100644 --- a/src/utils/farms/claiming.ts +++ b/src/utils/farms/claiming.ts @@ -31,13 +31,9 @@ export const useClaimableAmount = ( const allDeposits = useUserDeposits() const filteredDeposits = poolId - ? { - ...allDeposits, - data: - allDeposits.data?.filter( - (deposit) => deposit.data.ammPoolId.toString() === poolId, - ) ?? [], - } + ? allDeposits.filter( + (deposit) => deposit.data.ammPoolId.toString() === poolId, + ) : allDeposits const omnipoolAssets = useOmnipoolAssets() @@ -89,7 +85,6 @@ export const useClaimableAmount = ( const queries = [ bestNumberQuery, - filteredDeposits, farms, inactiveFarms, accountBalances, @@ -100,14 +95,13 @@ export const useClaimableAmount = ( const data = useMemo(() => { if ( !bestNumberQuery.data || - !filteredDeposits.data || + !filteredDeposits || !accountBalances.data || !spotPrices.data ) return undefined - const deposits = - depositNft != null ? [depositNft] : filteredDeposits.data ?? [] + const deposits = depositNft != null ? [depositNft] : filteredDeposits ?? [] const bestNumber = bestNumberQuery const multiCurrency = new MultiCurrencyContainer( @@ -207,7 +201,7 @@ export const useClaimableAmount = ( bestNumberQuery, depositNft, allFarms, - filteredDeposits.data, + filteredDeposits, metas, oraclePrices, spotPrices.data, @@ -229,10 +223,10 @@ export const useClaimAllMutation = ( const allUserDeposits = useUserDeposits() const filteredDeposits = poolId - ? allUserDeposits.data?.filter( + ? allUserDeposits.filter( (deposit) => deposit.data.ammPoolId.toString() === poolId.toString(), ) ?? [] - : allUserDeposits.data + : allUserDeposits const deposits = depositNft ? [depositNft] : filteredDeposits diff --git a/src/utils/queryKeys.ts b/src/utils/queryKeys.ts index 194f33124..2fa56b2ef 100644 --- a/src/utils/queryKeys.ts +++ b/src/utils/queryKeys.ts @@ -58,6 +58,11 @@ export const QUERY_KEYS = { ], deposit: (id: Maybe) => [QUERY_KEY_PREFIX, "deposit", id?.toString()], allDeposits: [QUERY_KEY_PREFIX, "deposits"], + omnipoolDeposits: (ids: string[]) => [ + QUERY_KEY_PREFIX, + "omnipoolDeposits", + ids.join("."), + ], poolDeposits: (poolId: Maybe) => [ QUERY_KEY_PREFIX, "deposits", From d6b3662e908b2fa1671f95080c45416836943714 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Sat, 13 Apr 2024 13:25:20 +0200 Subject: [PATCH 015/103] wip --- src/api/deposits.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/deposits.ts b/src/api/deposits.ts index dc957bccb..70da62c3d 100644 --- a/src/api/deposits.ts +++ b/src/api/deposits.ts @@ -67,9 +67,11 @@ export const useUserDeposits = (address?: string) => { const nftPositions = useAccountOmnipoolPositions(address) const { miningNfts = [] } = nftPositions.data ?? {} + const omnipoolDeposits = - useOmnipoolDeposits(miningNfts.map((miningNft) => miningNft.instanceId)) - .data ?? [] + useOmnipoolDeposits( + miningNfts.map((miningNft) => miningNft.instanceId), + ).data?.filter((deposit) => deposit.data) ?? [] return omnipoolDeposits } From 4cc29980e86c7f2df0df24d3168bb60410e287b4 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Mon, 15 Apr 2024 11:51:05 +0200 Subject: [PATCH 016/103] Claim all deposits --- src/api/deposits.ts | 5 ++ src/api/farms.ts | 6 -- .../claimAllDropdown/ClaimAllContent.tsx | 4 +- .../claimableCard/ClaimRewardsCard.tsx | 8 +- src/utils/farms/claiming.ts | 75 +++++++++++++------ 5 files changed, 64 insertions(+), 34 deletions(-) diff --git a/src/api/deposits.ts b/src/api/deposits.ts index dbb243f95..d46966599 100644 --- a/src/api/deposits.ts +++ b/src/api/deposits.ts @@ -6,6 +6,11 @@ import { useRpcProvider } from "providers/rpcProvider" import { useAccountNFTPositions } from "sections/pools/PoolsPage.utils" import { PalletLiquidityMiningDepositData } from "@polkadot/types/lookup" +export type TDeposit = { + id: string + data: PalletLiquidityMiningDepositData +} + export const useOmnipoolDeposits = (ids: string[]) => { const { api } = useRpcProvider() diff --git a/src/api/farms.ts b/src/api/farms.ts index 1e88102ee..71d8cbbef 100644 --- a/src/api/farms.ts +++ b/src/api/farms.ts @@ -36,12 +36,6 @@ export interface Farm { poolId: string } -export const useFarmingPoolAssets = () => { - const { assets } = useRpcProvider() - - console.log(assets.tradeAssets, assets.shareTokens) -} - export function useActiveYieldFarms(poolIds: Array) { const { api, assets } = useRpcProvider() diff --git a/src/sections/pools/farms/components/claimAllDropdown/ClaimAllContent.tsx b/src/sections/pools/farms/components/claimAllDropdown/ClaimAllContent.tsx index ce0bfb1c1..8fa3e8e71 100644 --- a/src/sections/pools/farms/components/claimAllDropdown/ClaimAllContent.tsx +++ b/src/sections/pools/farms/components/claimAllDropdown/ClaimAllContent.tsx @@ -2,7 +2,7 @@ import { forwardRef } from "react" import { ToastMessage } from "state/store" import { Trans, useTranslation } from "react-i18next" import { useRpcProvider } from "providers/rpcProvider" -import { useClaimableAmount, useClaimAllMutation } from "utils/farms/claiming" +import { useClaimableAmount, useClaimFarmMutation } from "utils/farms/claiming" import { TOAST_MESSAGES } from "state/toasts" import { DisplayValue } from "components/DisplayValue/DisplayValue" import { SClaimButton, SContent } from "./ClaimAllDrowpdown.styled" @@ -46,7 +46,7 @@ export const ClaimAllContent = forwardRef( return memo }, {} as ToastMessage) - const claimAll = useClaimAllMutation(undefined, undefined, toast) + const claimAll = useClaimFarmMutation(undefined, undefined, toast) return ( void }) => { const { t } = useTranslation() @@ -67,7 +67,7 @@ export const ClaimRewardsCard = (props: { return memo }, {} as ToastMessage) - const claimAll = useClaimAllMutation( + const claimAll = useClaimFarmMutation( props.poolId, props.depositNft, toast, diff --git a/src/utils/farms/claiming.ts b/src/utils/farms/claiming.ts index ec9c42141..26cd6196c 100644 --- a/src/utils/farms/claiming.ts +++ b/src/utils/farms/claiming.ts @@ -3,12 +3,11 @@ import { AccountId32 } from "@polkadot/types/interfaces" import { useMutation } from "@tanstack/react-query" import { useAccountAssetBalances } from "api/accountBalances" import { useBestNumber } from "api/chain" -import { useUserDeposits } from "api/deposits" +import { TDeposit, useUserDeposits } from "api/deposits" import { useFarms, useInactiveFarms, useOraclePrices } from "api/farms" import { useOmnipoolAssets } from "api/omnipool" import BigNumber from "bignumber.js" import { useMemo } from "react" -import { TMiningNftPosition } from "sections/pools/PoolsPage.utils" import { ToastMessage, useStore } from "state/store" import { getFloatingPointAmount } from "utils/balance" import { BN_0 } from "utils/constants" @@ -19,10 +18,7 @@ import { MultiCurrencyContainer } from "./claiming/multiCurrency" import { createMutableFarmEntries } from "./claiming/mutableFarms" import { useRpcProvider } from "providers/rpcProvider" -export const useClaimableAmount = ( - poolId?: string, - depositNft?: TMiningNftPosition, -) => { +export const useClaimableAmount = (poolId?: string, depositNft?: TDeposit) => { const bestNumberQuery = useBestNumber() const { api, assets } = useRpcProvider() const { omnipoolDeposits, xykDeposits } = useUserDeposits() @@ -220,31 +216,50 @@ export const useClaimableAmount = ( return { data, isLoading } } -export const useClaimAllMutation = ( +export const useClaimFarmMutation = ( poolId?: string, - depositNft?: TMiningNftPosition, + depositNft?: TDeposit, toast?: ToastMessage, onClose?: () => void, onBack?: () => void, ) => { - const { api } = useRpcProvider() + const { api, assets } = useRpcProvider() const { createTransaction } = useStore() + const meta = poolId ? assets.getAsset(poolId) : undefined + const isXYK = assets.isShareToken(meta) - //TODO: ADD xykDeposits as well - const { omnipoolDeposits } = useUserDeposits() + const { omnipoolDeposits, xykDeposits } = useUserDeposits() - const filteredDeposits = poolId - ? omnipoolDeposits.filter( - (deposit) => deposit.data.ammPoolId.toString() === poolId.toString(), - ) ?? [] - : omnipoolDeposits + let omnipoolDeposits_: TDeposit[] = [] + let xykDeposits_: TDeposit[] = [] - const deposits = depositNft ? [depositNft] : filteredDeposits + if (depositNft) { + if (isXYK) { + xykDeposits_ = [depositNft] + } else { + omnipoolDeposits_ = [depositNft] + } + } else { + if (poolId) { + if (isXYK) { + xykDeposits_ = xykDeposits.filter( + (deposit) => deposit.data.ammPoolId.toString() === meta.poolAddress, + ) + } else { + omnipoolDeposits_ = omnipoolDeposits.filter( + (deposit) => deposit.data.ammPoolId.toString() === poolId, + ) + } + } else { + xykDeposits_ = xykDeposits + omnipoolDeposits_ = omnipoolDeposits + } + } return useMutation(async () => { - const txs = - deposits - ?.map((deposit) => + const omnipoolTxs = + omnipoolDeposits_ + .map((deposit) => deposit.data.yieldFarmEntries.map((entry) => api.tx.omnipoolLiquidityMining.claimRewards( deposit.id, @@ -254,9 +269,25 @@ export const useClaimAllMutation = ( ) .flat(2) ?? [] - if (txs.length > 0) { + const xykTxs = + xykDeposits_ + .map((deposit) => + deposit.data.yieldFarmEntries.map((entry) => + api.tx.xykLiquidityMining.claimRewards( + deposit.id, + entry.yieldFarmId, + ), + ), + ) + .flat(2) ?? [] + + const allTxs = [...omnipoolTxs, ...xykTxs] + + if (allTxs.length > 0) { return await createTransaction( - { tx: txs.length > 1 ? api.tx.utility.forceBatch(txs) : txs[0] }, + { + tx: allTxs.length > 1 ? api.tx.utility.forceBatch(allTxs) : allTxs[0], + }, { toast, onBack, onClose }, ) } From a402667ff888c74bb341e2274423df21b1888b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Mon, 15 Apr 2024 13:24:39 +0200 Subject: [PATCH 017/103] Silent WalletConnect relay connection fail --- .../web3-connect/wallets/WalletConnect.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/sections/web3-connect/wallets/WalletConnect.ts b/src/sections/web3-connect/wallets/WalletConnect.ts index 7fe0a1876..671ba9b17 100644 --- a/src/sections/web3-connect/wallets/WalletConnect.ts +++ b/src/sections/web3-connect/wallets/WalletConnect.ts @@ -80,7 +80,11 @@ const namespaces = { export type NamespaceType = keyof typeof namespaces -const provider = await UniversalProvider.init(walletConnectParams) +const provider = await UniversalProvider.init(walletConnectParams).catch( + (err) => { + console.error(err) + }, +) type ModalSubFn = (session?: SessionTypes.Struct) => void @@ -181,6 +185,8 @@ export class WalletConnect implements Wallet { subscribeToProviderEvents = () => { const provider = this.rawExtension + if (!provider) return + provider.on("display_uri", this.onDisplayUri) provider.on("session_update", this.onSessionUpdate) } @@ -196,9 +202,15 @@ export class WalletConnect implements Wallet { ) } - try { - const provider = this.rawExtension + const provider = this.rawExtension + if (!provider) { + throw new Error( + "WalletConnectError: Connection failed. Please try again.", + ) + } + + try { const session = await provider.connect({ namespaces: this.namespace, }) @@ -209,7 +221,6 @@ export class WalletConnect implements Wallet { ) } - this._extension = provider this._session = session const accounts = await this.getAccounts() From 8358a951fb70a9ca0e30dae487975cb6a1ff0f7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Mon, 15 Apr 2024 17:21:53 +0200 Subject: [PATCH 018/103] Initialize WalletConnect provider only when needed --- .../web3-connect/Web3Connect.utils.ts | 5 ++ .../accounts/Web3ConnectAccount.tsx | 5 +- .../web3-connect/wallets/WalletConnect.ts | 53 +++++++++++-------- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/sections/web3-connect/Web3Connect.utils.ts b/src/sections/web3-connect/Web3Connect.utils.ts index ccee9a282..d73fe03b4 100644 --- a/src/sections/web3-connect/Web3Connect.utils.ts +++ b/src/sections/web3-connect/Web3Connect.utils.ts @@ -31,6 +31,7 @@ import { WalletAccount } from "sections/web3-connect/types" import { EVM_PROVIDERS } from "sections/web3-connect/constants/providers" import { useAddressStore } from "components/AddressBook/AddressBook.utils" import { EthereumSigner } from "sections/web3-connect/signer/EthereumSigner" +import { PolkadotSigner } from "sections/web3-connect/signer/PolkadotSigner" export type { WalletProvider } from "./wallets" export { WalletProviderType, getSupportedWallets } @@ -340,6 +341,10 @@ export function getWalletProviderByType(type?: WalletProviderType | null) { function getProviderQueryKey(type: WalletProviderType | null) { const { wallet } = getWalletProviderByType(type) + if (wallet?.signer instanceof PolkadotSigner) { + return [type, wallet.signer?.session?.topic].join("-") + } + if (wallet?.signer instanceof EthereumSigner) { return [type, wallet.signer?.address].join("-") } diff --git a/src/sections/web3-connect/accounts/Web3ConnectAccount.tsx b/src/sections/web3-connect/accounts/Web3ConnectAccount.tsx index c6b346a73..a7521ea62 100644 --- a/src/sections/web3-connect/accounts/Web3ConnectAccount.tsx +++ b/src/sections/web3-connect/accounts/Web3ConnectAccount.tsx @@ -10,6 +10,7 @@ import { genesisHashToChain } from "utils/helpers" import { DisplayValue } from "components/DisplayValue/DisplayValue" import BN from "bignumber.js" import { availableNetworks } from "@polkadot/networks" +import { isEvmAccount } from "utils/evm" type Props = Account & { isProxy?: boolean @@ -32,7 +33,9 @@ export const Web3ConnectAccount: FC = ({ const { hydraAddress } = getAddressVariants(address) - const chain = genesisHashToChain(genesisHash) + const chain = !isEvmAccount(address) + ? genesisHashToChain(genesisHash) + : undefined const addr = displayAddress || hydraAddress const isHydraAddr = addr && isHydraAddress(addr) diff --git a/src/sections/web3-connect/wallets/WalletConnect.ts b/src/sections/web3-connect/wallets/WalletConnect.ts index 671ba9b17..4ff2a10f5 100644 --- a/src/sections/web3-connect/wallets/WalletConnect.ts +++ b/src/sections/web3-connect/wallets/WalletConnect.ts @@ -47,7 +47,6 @@ const POLKADOT_CHAIN_IDS = Object.values(POLKADOT_CAIP_ID_MAP) const walletConnectParams = { projectId: WC_PROJECT_ID, relayUrl: "wss://relay.walletconnect.com", - logger: "debug", metadata: { name: POLKADOT_APP_NAME, description: POLKADOT_APP_NAME, @@ -80,12 +79,6 @@ const namespaces = { export type NamespaceType = keyof typeof namespaces -const provider = await UniversalProvider.init(walletConnectParams).catch( - (err) => { - console.error(err) - }, -) - type ModalSubFn = (session?: SessionTypes.Struct) => void export class WalletConnect implements Wallet { @@ -114,7 +107,6 @@ export class WalletConnect implements Wallet { projectId: WC_PROJECT_ID, }) - this.subscribeToProviderEvents() this.subscribeToModalEvents(onModalOpen, onModalClose) } @@ -139,6 +131,30 @@ export class WalletConnect implements Wallet { } get rawExtension() { + return this._extension + } + + initializeProvider = async () => { + if (this.extension) { + return Promise.resolve(this.extension) + } + + const provider = await UniversalProvider.init(walletConnectParams).catch( + (err) => { + console.error(err) + }, + ) + + if (!provider) { + throw new Error( + "WalletConnectError: Connection failed. Please try again.", + ) + } + + this._extension = provider + provider.on("display_uri", this.onDisplayUri) + provider.on("session_update", this.onSessionUpdate) + return provider } @@ -182,15 +198,6 @@ export class WalletConnect implements Wallet { this._session = session } - subscribeToProviderEvents = () => { - const provider = this.rawExtension - - if (!provider) return - - provider.on("display_uri", this.onDisplayUri) - provider.on("session_update", this.onSessionUpdate) - } - enable = async (dappName: string) => { if (!dappName) { throw new Error("MissingParamsError: Dapp name is required.") @@ -202,11 +209,11 @@ export class WalletConnect implements Wallet { ) } - const provider = this.rawExtension + const provider = await this.initializeProvider() if (!provider) { throw new Error( - "WalletConnectError: Connection failed. Please try again.", + "WalletConnectError: WalletConnect provider is not initialized.", ) } @@ -217,7 +224,7 @@ export class WalletConnect implements Wallet { if (!session) { throw new Error( - "WalletConnectError: Failed to connect to WalletConnect.", + "WalletConnectError: Failed to create WalletConnect sessopm.", ) } @@ -227,14 +234,14 @@ export class WalletConnect implements Wallet { const namespace = Object.keys(this.namespace).pop() as NamespaceType - if (namespace === "eip155") { + if (namespace === "eip155" && provider instanceof UniversalProvider) { const mainAddress = accounts[0]?.address this._signer = mainAddress - ? new EthereumSigner(mainAddress, this.rawExtension) + ? new EthereumSigner(mainAddress, provider) : undefined } - if (namespace === "polkadot") { + if (namespace === "polkadot" && provider.client) { this._signer = new PolkadotSigner(provider.client, session) } } finally { From 336d6d58ecd75935267bcf49e16bb8f4e8672490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Mon, 15 Apr 2024 17:34:56 +0200 Subject: [PATCH 019/103] Use Display Asset for OTC offer price --- src/i18n/locales/en/translations.json | 2 +- src/sections/trade/sections/otc/orders/OtcOrdersData.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/i18n/locales/en/translations.json b/src/i18n/locales/en/translations.json index 1f171876e..24b892d4a 100644 --- a/src/i18n/locales/en/translations.json +++ b/src/i18n/locales/en/translations.json @@ -367,7 +367,7 @@ "otc.offers.table.header.offer": "Offer", "otc.offers.table.header.accepting": "Accepting", "otc.offers.table.header.assets": "Assets", - "otc.offers.table.header.orderPrice": "Offer USD Price", + "otc.offers.table.header.orderPrice": "Offer Price", "otc.offers.table.header.perToken": "per {{ symbol }}", "otc.offers.table.header.marketPrice": "Market Price", "otc.offers.table.header.status": "Order status", diff --git a/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx b/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx index c7bdb0f7e..715d23f5d 100644 --- a/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx +++ b/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx @@ -9,6 +9,7 @@ import { useRpcProvider } from "providers/rpcProvider" import { abbreviateNumber } from "utils/helpers" import { useMedia } from "react-use" import { theme } from "theme" +import { DisplayValue } from "components/DisplayValue/DisplayValue" export const OrderPairColumn = (props: { offering: OfferingPair @@ -176,7 +177,7 @@ export const OrderPriceColumn = (props: { pair: OfferingPair; price: BN }) => { ) : ( <> - {abbreviateNumber(props.price)} + ( From 0a2453a15b6a1663572c913d1903b8547f03e5c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Mon, 15 Apr 2024 17:35:52 +0200 Subject: [PATCH 020/103] removed unused import --- src/sections/trade/sections/otc/orders/OtcOrdersData.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx b/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx index 715d23f5d..3e543ef6a 100644 --- a/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx +++ b/src/sections/trade/sections/otc/orders/OtcOrdersData.tsx @@ -6,7 +6,6 @@ import { Text } from "components/Typography/Text/Text" import { useTranslation } from "react-i18next" import { OfferingPair } from "./OtcOrdersData.utils" import { useRpcProvider } from "providers/rpcProvider" -import { abbreviateNumber } from "utils/helpers" import { useMedia } from "react-use" import { theme } from "theme" import { DisplayValue } from "components/DisplayValue/DisplayValue" From ef540ceff0983af70b75c0dee8dd6881e9bae143 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Mon, 15 Apr 2024 18:43:51 +0200 Subject: [PATCH 021/103] display xyk deposits --- src/api/balances.ts | 25 ++ src/api/deposits.ts | 68 ++++- src/api/omnipool.ts | 13 +- .../Layout/Header/menu/HeaderMenu.tsx | 2 +- src/providers/rpcProvider.tsx | 5 + src/sections/pools/PoolsPage.utils.ts | 259 ++++++------------ .../claimAllDropdown/ClaimAllDropdown.tsx | 6 +- .../pools/farms/position/FarmingPosition.tsx | 15 +- .../farms/position/FarmingPosition.utils.tsx | 149 +++++----- src/sections/pools/header/MyFarmsTotal.tsx | 21 +- .../pools/header/MyLiquidityTotal.tsx | 22 +- src/sections/pools/navigation/Navigation.tsx | 2 +- .../pools/pool/myPositions/MyPositions.tsx | 4 +- .../wallet/assets/WalletAssets.utils.ts | 24 +- .../WalletFarmingPositions.tsx | 2 +- .../WalletFarmingPositions.utils.tsx | 222 ++++++++++----- .../details/FarmingPositionsDetailsMob.tsx | 96 ++++--- .../WalletAssetsHydraPositions.utils.tsx | 42 +-- .../WalletAssetsHydraPositionsData.utils.tsx | 11 +- .../WalletAssetsHydraPositionsDetails.tsx | 83 ++++-- src/utils/omnipool.ts | 3 +- 21 files changed, 562 insertions(+), 512 deletions(-) diff --git a/src/api/balances.ts b/src/api/balances.ts index 625cc44b8..a60d20ad6 100644 --- a/src/api/balances.ts +++ b/src/api/balances.ts @@ -159,3 +159,28 @@ export const getTokenLock = type: lock.id.toString(), })) } + +export const useShareTokenBalances = (shareTokenIds: string[]) => { + const { api, assets } = useRpcProvider() + + const shareTokens = assets + .getAssets(shareTokenIds) + .reduce<{ id: string; address: string }[]>((acc, asset) => { + if (assets.isShareToken(asset)) { + asset.assets.forEach((id) => + acc.push({ id, address: asset.poolAddress }), + ) + } + + return acc + }, []) + + return useQueries({ + queries: shareTokens.map(({ id, address }) => ({ + queryKey: QUERY_KEYS.tokenBalanceLive(id, address), + queryFn: + address != null ? getTokenBalance(api, address, id) : undefinedNoop, + enabled: !!id && !!address, + })), + }) +} diff --git a/src/api/deposits.ts b/src/api/deposits.ts index d46966599..f4a651c7d 100644 --- a/src/api/deposits.ts +++ b/src/api/deposits.ts @@ -3,8 +3,9 @@ import { u128, u32, Option } from "@polkadot/types" import { useQueries, useQuery } from "@tanstack/react-query" import { QUERY_KEYS } from "utils/queryKeys" import { useRpcProvider } from "providers/rpcProvider" -import { useAccountNFTPositions } from "sections/pools/PoolsPage.utils" import { PalletLiquidityMiningDepositData } from "@polkadot/types/lookup" +import { undefinedNoop } from "utils/helpers" +import { useAccount } from "sections/web3-connect/Web3Connect.utils" export type TDeposit = { id: string @@ -50,9 +51,13 @@ const getDeposits = ) as PalletLiquidityMiningDepositData, ) - const test = ids.map((id, i) => ({ id, data: data[i] })) + const data_ = ids.map((id, i) => ({ + id, + data: data[i], + isXyk: type === "xyk", + })) - return test + return data_ } export const useOmniPositionIds = (positionIds: Array) => { @@ -73,6 +78,63 @@ const getOmniPositionId = return { depositionId, value: res.value } } +export const useAccountNFTPositions = (givenAddress?: string) => { + const { account } = useAccount() + const { api } = useRpcProvider() + + const address = givenAddress ?? account?.address + + return useQuery( + QUERY_KEYS.accountOmnipoolPositions(address), + address != null + ? async () => { + const [omnipoolNftId, miningNftId, xykMiningNftId] = + await Promise.all([ + api.consts.omnipool.nftCollectionId, + api.consts.omnipoolLiquidityMining.nftCollectionId, + api.consts.xykLiquidityMining.nftCollectionId, + ]) + const [omnipoolNftsRaw, miningNftsRaw, xykMiningNftsRaw] = + await Promise.all([ + api.query.uniques.account.entries(address, omnipoolNftId), + api.query.uniques.account.entries(address, miningNftId), + api.query.uniques.account.entries(address, xykMiningNftId), + ]) + + const omnipoolNfts = omnipoolNftsRaw.map(([storageKey]) => { + const [owner, classId, instanceId] = storageKey.args + return { + owner: owner.toString(), + classId: classId.toString(), + instanceId: instanceId.toString(), + } + }) + + const miningNfts = miningNftsRaw.map(([storageKey]) => { + const [owner, classId, instanceId] = storageKey.args + return { + owner: owner.toString(), + classId: classId.toString(), + instanceId: instanceId.toString(), + } + }) + + const xykMiningNfts = xykMiningNftsRaw.map(([storageKey]) => { + const [owner, classId, instanceId] = storageKey.args + return { + owner: owner.toString(), + classId: classId.toString(), + instanceId: instanceId.toString(), + } + }) + + return { omnipoolNfts, miningNfts, xykMiningNfts } + } + : undefinedNoop, + { enabled: !!address }, + ) +} + export const useUserDeposits = (address?: string) => { const nftPositions = useAccountNFTPositions(address) diff --git a/src/api/omnipool.ts b/src/api/omnipool.ts index 83fb889b8..c2443cac2 100644 --- a/src/api/omnipool.ts +++ b/src/api/omnipool.ts @@ -2,7 +2,6 @@ import { useQueries, useQuery } from "@tanstack/react-query" import { ApiPromise } from "@polkadot/api" import { QUERY_KEYS } from "utils/queryKeys" import { u128, u32 } from "@polkadot/types-codec" -import { ITuple } from "@polkadot/types-codec/types" import { undefinedNoop } from "utils/helpers" import { REFETCH_INTERVAL } from "utils/constants" import { useRpcProvider } from "providers/rpcProvider" @@ -92,19 +91,15 @@ export const getOmnipoolFee = (api: ApiPromise) => async () => { } } -export type OmnipoolPosition = { - id: string - assetId: u32 - amount: u128 - shares: u128 - price: ITuple<[u128, u128]> -} +export type OmnipoolPosition = Awaited< + ReturnType> +> export const getOmnipoolPosition = (api: ApiPromise, itemId: string) => async () => { const res = await api.query.omnipool.positions(itemId) const data = res.unwrap() - const position: OmnipoolPosition = { + const position = { id: itemId, assetId: data.assetId, amount: data.amount, diff --git a/src/components/Layout/Header/menu/HeaderMenu.tsx b/src/components/Layout/Header/menu/HeaderMenu.tsx index 2f3eea1b2..fd5ac275d 100644 --- a/src/components/Layout/Header/menu/HeaderMenu.tsx +++ b/src/components/Layout/Header/menu/HeaderMenu.tsx @@ -6,8 +6,8 @@ import { HeaderSubMenu } from "./HeaderSubMenu" import { forwardRef } from "react" import { useRpcProvider } from "providers/rpcProvider" import { useAccount } from "sections/web3-connect/Web3Connect.utils" -import { useAccountNFTPositions } from "sections/pools/PoolsPage.utils" import { useTokensBalances } from "api/balances" +import { useAccountNFTPositions } from "api/deposits" export const HeaderMenu = forwardRef((_, ref) => { const { t } = useTranslation() diff --git a/src/providers/rpcProvider.tsx b/src/providers/rpcProvider.tsx index d7b0fb81a..cc0ca70c7 100644 --- a/src/providers/rpcProvider.tsx +++ b/src/providers/rpcProvider.tsx @@ -21,6 +21,7 @@ type IContextAssets = Awaited>["assets"] & { getAsset: (id: string) => TAsset getBond: (id: string) => TBond | undefined getAssets: (ids: string[]) => TAsset[] + getShareTokenByAddress: (address: string) => TShareToken | undefined tradeAssets: TAsset[] } @@ -93,6 +94,9 @@ export const RpcProvider = ({ children }: { children: ReactNode }) => { return asset.isShareToken } + const getShareTokenByAddress = (address: string) => + shareTokens.find((shareToken) => shareToken.poolAddress === address) + const getAsset = (id: string) => allTokensObject[id] ?? fallbackAsset const getBond = (id: string) => { @@ -118,6 +122,7 @@ export const RpcProvider = ({ children }: { children: ReactNode }) => { getAsset, getBond, getAssets, + getShareTokenByAddress, tradeAssets, }, api: providerData.data.api, diff --git a/src/sections/pools/PoolsPage.utils.ts b/src/sections/pools/PoolsPage.utils.ts index b6dcc402a..fe0723190 100644 --- a/src/sections/pools/PoolsPage.utils.ts +++ b/src/sections/pools/PoolsPage.utils.ts @@ -1,4 +1,8 @@ -import { useTokenBalance, useTokensBalances } from "api/balances" +import { + useShareTokenBalances, + useTokenBalance, + useTokensBalances, +} from "api/balances" import { useHubAssetTradability, useOmnipoolAssets } from "api/omnipool" import { useMemo } from "react" import { useAccount } from "sections/web3-connect/Web3Connect.utils" @@ -16,10 +20,7 @@ import { encodeAddress, blake2AsHex } from "@polkadot/util-crypto" import { HYDRADX_SS58_PREFIX, XykMath } from "@galacticcouncil/sdk" import { useAccountBalances } from "api/accountBalances" import { useRpcProvider } from "providers/rpcProvider" -import { useQueries, useQuery } from "@tanstack/react-query" -import { QUERY_KEYS } from "utils/queryKeys" -import { isNotNil, undefinedNoop } from "utils/helpers" -import { ApiPromise } from "@polkadot/api" +import { isNotNil } from "utils/helpers" import { useOmnipoolPositionsData } from "sections/wallet/assets/hydraPositions/data/WalletAssetsHydraPositionsData.utils" import { useVolume } from "api/volume" import BN from "bignumber.js" @@ -32,7 +33,7 @@ import { import { useShareOfPools } from "api/pools" import { TShareToken } from "api/assetDetails" import { useXYKPoolTradeVolumes } from "./pool/details/PoolDetails.utils" -import { useAllUserDepositShare } from "./farms/position/FarmingPosition.utils" +import { useAllOmnipoolDeposits } from "./farms/position/FarmingPosition.utils" import { useFee } from "api/stats" import { useTVL } from "api/stats" import { scaleHuman } from "utils/balance" @@ -42,8 +43,7 @@ import { is_remove_liquidity_allowed, is_sell_allowed, } from "@galacticcouncil/math-omnipool" -import { Option } from "@polkadot/types" -import { PalletLiquidityMiningDepositData } from "@polkadot/types/lookup" +import { useUserDeposits } from "api/deposits" export const useAssetsTradability = () => { const { @@ -104,122 +104,15 @@ export type TPoolFullData = TPool & TPoolDetails export type TXYKPoolFullData = TXYKPool & NonNullable["data"]> +export type TXYKPool = NonNullable< + ReturnType["data"] +>[number] + export const derivePoolAccount = (assetId: string) => { const name = pool_account_name(Number(assetId)) return encodeAddress(blake2AsHex(name), HYDRADX_SS58_PREFIX) } -export const useAccountNFTPositions = (givenAddress?: string) => { - const { account } = useAccount() - const { api } = useRpcProvider() - - const address = givenAddress ?? account?.address - - return useQuery( - QUERY_KEYS.accountOmnipoolPositions(address), - address != null - ? async () => { - const [omnipoolNftId, miningNftId, xykMiningNftId] = - await Promise.all([ - api.consts.omnipool.nftCollectionId, - api.consts.omnipoolLiquidityMining.nftCollectionId, - api.consts.xykLiquidityMining.nftCollectionId, - ]) - const [omnipoolNftsRaw, miningNftsRaw, xykMiningNftsRaw] = - await Promise.all([ - api.query.uniques.account.entries(address, omnipoolNftId), - api.query.uniques.account.entries(address, miningNftId), - api.query.uniques.account.entries(address, xykMiningNftId), - ]) - - const omnipoolNfts = omnipoolNftsRaw.map(([storageKey]) => { - const [owner, classId, instanceId] = storageKey.args - return { - owner: owner.toString(), - classId: classId.toString(), - instanceId: instanceId.toString(), - } - }) - - const miningNfts = miningNftsRaw.map(([storageKey]) => { - const [owner, classId, instanceId] = storageKey.args - return { - owner: owner.toString(), - classId: classId.toString(), - instanceId: instanceId.toString(), - } - }) - - const xykMiningNfts = xykMiningNftsRaw.map(([storageKey]) => { - const [owner, classId, instanceId] = storageKey.args - return { - owner: owner.toString(), - classId: classId.toString(), - instanceId: instanceId.toString(), - } - }) - - return { omnipoolNfts, miningNfts, xykMiningNfts } - } - : undefinedNoop, - { enabled: !!address }, - ) -} - -export const useAccountMiningPositions = () => { - const { api } = useRpcProvider() - const { data } = useAccountNFTPositions() - - return useQueries({ - queries: data?.miningNfts - ? data.miningNfts.map((nft) => ({ - queryKey: QUERY_KEYS.miningPosition(nft.instanceId), - queryFn: getMiningPosition(api, nft.instanceId), - enabled: !!nft.instanceId, - })) - : [], - }) -} - -export const useAccountXYKMiningPositions = () => { - const { api } = useRpcProvider() - const { data } = useAccountNFTPositions() - - return useQueries({ - queries: data?.xykMiningNfts - ? data.xykMiningNfts.map((nft) => ({ - queryKey: QUERY_KEYS.miningPositionXYK(nft.instanceId), - queryFn: getMiningPositionXYK(api, nft.instanceId), - enabled: !!nft.instanceId, - })) - : [], - }) -} - -const getMiningPosition = (api: ApiPromise, id: string) => async () => { - const key = api.query.omnipoolWarehouseLM.deposit.key(id) - - const value = (await api.rpc.state.getStorage( - key, - )) as Option - - if (value.isNone) return undefined - - const data = api.registry.createType( - "OmnipoolLMDeposit", - value.unwrap(), - ) as PalletLiquidityMiningDepositData - - return { id, data } -} - -const getMiningPositionXYK = (api: ApiPromise, id: string) => async () => { - const dataRaw = await api.query.xykWarehouseLM.deposit(id) - const data = dataRaw.unwrap() - - return { id, data } -} - const getTradeFee = (fee: string[]) => { if (fee?.length !== 2) return BN_NAN @@ -230,10 +123,6 @@ const getTradeFee = (fee: string[]) => { return tradeFee.times(100) } -export type TXYKPool = NonNullable< - ReturnType["data"] ->[number] - export const usePools = () => { const { assets } = useRpcProvider() const { stableCoinId } = useDisplayAssetStore() @@ -244,7 +133,7 @@ export const usePools = () => { const assetsTradability = useAssetsTradability() const omnipoolPositions = useOmnipoolPositionsData() - const miningPositions = useAllUserDepositShare() + const miningPositions = useAllOmnipoolDeposits() const assetsId = useMemo( () => omnipoolAssets.data?.map((a) => a.id.toString()) ?? [], @@ -389,7 +278,7 @@ export const usePoolDetails = (assetId: string) => { const meta = assets.getAsset(assetId) const isStablePool = assets.isStableSwap(meta) - const miningPositions = useAccountMiningPositions() + const { omnipoolDeposits } = useUserDeposits() const omnipoolPositions = useOmnipoolPositionsData() const poolAccountAddress = derivePoolAccount(assetId) @@ -407,12 +296,8 @@ export const usePoolDetails = (assetId: string) => { (position) => position.assetId === assetId, ) - const miningNftPositions = miningPositions - .filter( - (position) => position.data?.data.ammPoolId.toString() === assetId, - ) - .map((position) => position.data) - .filter(isNotNil) + const miningNftPositions = omnipoolDeposits + .filter((position) => position.data.ammPoolId.toString() === assetId) .sort((a, b) => { const firstFarmLastBlock = a.data.yieldFarmEntries.reduce( (acc, curr) => @@ -459,7 +344,7 @@ export const usePoolDetails = (assetId: string) => { assetId, assets, isStablePool, - miningPositions, + omnipoolDeposits, omnipoolPositions.data, stablePoolBalance.data?.balances, stablepool.data?.fee, @@ -475,7 +360,7 @@ export const useMyPools = () => { const pools = usePools() const omnipoolPositions = useOmnipoolPositionsData() - const miningPositions = useAllUserDepositShare() + const miningPositions = useAllOmnipoolDeposits() const stableswapsId = assets.stableswap.map((shareToken) => shareToken.id) @@ -621,17 +506,14 @@ export const useXYKPools = (withPositions?: boolean) => { export const useXYKPoolDetails = (pool: TXYKPool) => { const volume = useXYKPoolTradeVolumes([pool.poolAddress]) - const miningPositions = useAccountXYKMiningPositions() + const { xykDeposits } = useUserDeposits() const isInitialLoading = volume.isLoading - const miningNftPositions = miningPositions + const miningNftPositions = xykDeposits .filter( - (position) => - position.data?.data.ammPoolId.toString() === pool.poolAddress, + (position) => position.data.ammPoolId.toString() === pool.poolAddress, ) - .map((position) => position.data) - .filter(isNotNil) .sort((a, b) => { const firstFarmLastBlock = a.data.yieldFarmEntries.reduce( (acc, curr) => @@ -695,16 +577,34 @@ export const useXYKSpotPrice = (shareTokenId: string) => { return { priceA, priceB, idA: metaA.id, idB: metaB.id } } -export const useDepositValues = ( - assetId: string, - depositNft: TMiningNftPosition, -) => { +export const useXYKDepositValues = (depositNfts: TMiningNftPosition[]) => { const { assets } = useRpcProvider() - const totalIssuances = useShareOfPools([assetId]) - const meta = assets.getAsset(assetId) as TShareToken + const depositNftsData = depositNfts.reduce< + { assetId: string; depositNft: TMiningNftPosition }[] + >((acc, depositNft) => { + const assetId = assets.getShareTokenByAddress( + depositNft.data.ammPoolId.toString(), + )?.id + + if (assetId) + acc.push({ + assetId, + depositNft, + }) + return acc + }, []) + + const uniqAssetIds = [ + ...new Set(depositNftsData.map((deposit) => deposit.assetId)), + ] + const totalIssuances = useShareOfPools(uniqAssetIds) + const balances = useShareTokenBalances(uniqAssetIds) + const shareTokeSpotPrices = useDisplayShareTokenPrice(uniqAssetIds) - const balances = useTokensBalances(meta.assets, meta.poolAddress) - const shareTokeSpotPrices = useDisplayShareTokenPrice([assetId]) + const isLoading = + totalIssuances.isInitialLoading || + balances.some((q) => q.isInitialLoading) || + shareTokeSpotPrices.isInitialLoading const data = useMemo(() => { const defaultValue = { @@ -713,46 +613,49 @@ export const useDepositValues = ( amountUSD: undefined, } - if ( - !totalIssuances.data || - balances.some((balance) => !balance.data) || - !shareTokeSpotPrices.data - ) - return defaultValue - - const shareTokenIssuance = totalIssuances.data?.[0].totalShare - - if (!shareTokenIssuance) { - console.error("Could not calculate deposit balances") - return defaultValue - } + return depositNftsData.map((deposit) => { + const shareTokenIssuance = totalIssuances.data?.find( + (totalIssuance) => totalIssuance.asset === deposit.assetId, + )?.totalShare - const shares = depositNft.data.shares.toBigNumber() - const ratio = shares.div(shareTokenIssuance) + if (!shareTokenIssuance) { + console.error("Could not calculate deposit balances") + return { ...defaultValue, assetId: deposit.assetId } + } - const amountUSD = scaleHuman(shareTokenIssuance, meta.decimals) - .multipliedBy(shareTokeSpotPrices.data?.[0]?.spotPrice ?? 1) - .times(ratio) + const shareTokenMeta = assets.getAsset(deposit.assetId) as TShareToken + const shares = deposit.depositNft.data.shares.toBigNumber() + const ratio = shares.div(shareTokenIssuance) + const amountUSD = scaleHuman(shareTokenIssuance, shareTokenMeta.decimals) + .multipliedBy(shareTokeSpotPrices.data?.[0]?.spotPrice ?? 1) + .times(ratio) + + const [assetA, assetB] = shareTokenMeta.assets.map((asset) => { + const meta = assets.getAsset(asset) + const balance = + balances.find( + (balance) => + balance.data?.assetId === asset && + balance.data?.accountId.toString() === shareTokenMeta.poolAddress, + )?.data?.balance ?? BN_0 + const amount = scaleHuman(balance.times(ratio), meta.decimals) - const [assetA, assetB] = meta.assets.map((asset) => { - const meta = assets.getAsset(asset) - const balance = - balances.find((balance) => balance.data?.assetId === asset)?.data - ?.balance ?? BN_0 - const amount = scaleHuman(balance.times(ratio), meta.decimals) - return { id: asset, symbol: meta.symbol, amount } + return { + id: asset, + symbol: meta.symbol, + decimals: meta.decimals, + amount, + } + }) + return { assetA, assetB, amountUSD, assetId: deposit.assetId } }) - - return { assetA, assetB, amountUSD } }, [ assets, balances, - depositNft.data.shares, - meta.assets, - meta.decimals, + depositNftsData, shareTokeSpotPrices.data, totalIssuances.data, ]) - return data + return { data, isLoading } } diff --git a/src/sections/pools/farms/components/claimAllDropdown/ClaimAllDropdown.tsx b/src/sections/pools/farms/components/claimAllDropdown/ClaimAllDropdown.tsx index b5d34fb59..5344ac48e 100644 --- a/src/sections/pools/farms/components/claimAllDropdown/ClaimAllDropdown.tsx +++ b/src/sections/pools/farms/components/claimAllDropdown/ClaimAllDropdown.tsx @@ -7,7 +7,7 @@ import { useTranslation } from "react-i18next" import { useMedia } from "react-use" import { HeaderSeparator } from "sections/pools/header/PoolsHeader" import { theme } from "theme" -import { useAllUserDepositShare } from "sections/pools/farms/position/FarmingPosition.utils" +import { useAllFarmDeposits } from "sections/pools/farms/position/FarmingPosition.utils" import { STriggerButton } from "./ClaimAllDrowpdown.styled" import { ClaimAllContent } from "./ClaimAllContent" @@ -15,9 +15,9 @@ export const ClaimAllDropdown = () => { const { t } = useTranslation() const [open, setOpen] = useState(false) const isDesktop = useMedia(theme.viewport.gte.sm) - const depositShares = useAllUserDepositShare() + const deposits = useAllFarmDeposits() - if (!Object.keys(depositShares.data).length) { + if (!Object.keys(deposits.omnipool).length && !deposits.xyk.length) { return null } diff --git a/src/sections/pools/farms/position/FarmingPosition.tsx b/src/sections/pools/farms/position/FarmingPosition.tsx index 02fe805c2..1fa625a61 100644 --- a/src/sections/pools/farms/position/FarmingPosition.tsx +++ b/src/sections/pools/farms/position/FarmingPosition.tsx @@ -5,7 +5,7 @@ import { useState } from "react" import { Trans, useTranslation } from "react-i18next" import { TMiningNftPosition, - useDepositValues, + useXYKDepositValues, } from "sections/pools/PoolsPage.utils" import { WalletAssetsHydraPositionsData } from "sections/wallet/assets/hydraPositions/data/WalletAssetsHydraPositionsData" import { useEnteredDate } from "utils/block" @@ -173,7 +173,7 @@ export const FarmingPosition = ({ {isXYK ? ( - + ) : ( )} @@ -267,15 +267,10 @@ const OmnipoolFields = ({ ) } -const XYKFields = ({ - poolId, - depositNft, -}: { - poolId: string - depositNft: TMiningNftPosition -}) => { +const XYKFields = ({ depositNft }: { depositNft: TMiningNftPosition }) => { const { t } = useTranslation() - const { amountUSD, assetA, assetB } = useDepositValues(poolId, depositNft) + const { amountUSD, assetA, assetB } = + useXYKDepositValues([depositNft]).data?.[0] ?? {} return ( diff --git a/src/sections/pools/farms/position/FarmingPosition.utils.tsx b/src/sections/pools/farms/position/FarmingPosition.utils.tsx index a7043a047..1637db72b 100644 --- a/src/sections/pools/farms/position/FarmingPosition.utils.tsx +++ b/src/sections/pools/farms/position/FarmingPosition.utils.tsx @@ -1,10 +1,5 @@ -import { - calculate_liquidity_lrna_out, - calculate_liquidity_out, -} from "@galacticcouncil/math-omnipool" import { u32 } from "@polkadot/types" import { useTokensBalances } from "api/balances" -import { useApiIds } from "api/consts" import { useOmniPositionIds, useUserDeposits } from "api/deposits" import { OmnipoolPosition, @@ -14,22 +9,14 @@ import { import BN from "bignumber.js" import { useMemo } from "react" import { OMNIPOOL_ACCOUNT_ADDRESS } from "utils/api" -import { BN_10, BN_NAN } from "utils/constants" import { useDisplayPrice, useDisplayPrices } from "utils/displayAsset" -import { normalizeBigNumber } from "utils/balance" import { useRpcProvider } from "providers/rpcProvider" +import { useXYKDepositValues } from "sections/pools/PoolsPage.utils" +import { calculatePositionLiquidity } from "utils/omnipool" +import { BN_0 } from "utils/constants" -export const useAllUserDepositShare = ({ - address, -}: { - address?: string -} = {}) => { +export const useOmnipoolDepositValues = (depositIds: string[]) => { const { assets } = useRpcProvider() - const { omnipoolDeposits } = useUserDeposits(address) - - const depositIds = omnipoolDeposits.map((deposit) => deposit.id) ?? [] - - const apiIds = useApiIds() const omnipoolAssets = useOmnipoolAssets() const omnipoolAssetIds = omnipoolAssets.data?.map((asset) => asset.id.toString()) ?? [] @@ -38,9 +25,7 @@ export const useAllUserDepositShare = ({ OMNIPOOL_ACCOUNT_ADDRESS, ) - const lrnaMeta = apiIds.data?.hubId - ? assets.getAsset(apiIds.data.hubId) - : undefined + const lrnaMeta = assets.hub const positionIds = useOmniPositionIds(depositIds ?? []) @@ -49,10 +34,9 @@ export const useAllUserDepositShare = ({ ) const spotPrices = useDisplayPrices(omnipoolAssetIds) - const lrnaSp = useDisplayPrice(apiIds.data?.hubId ?? "") + const lrnaSp = useDisplayPrice(lrnaMeta.id) const queries = [ - apiIds, omnipoolAssets, lrnaSp, spotPrices, @@ -90,62 +74,25 @@ export const useAllUserDepositShare = ({ meta && omnipoolAsset?.data && position.data && - lrnaMeta && spotPrice && lrnaSp.data ) { - let lernaOutResult = "-1" - let liquidityOutResult = "-1" - - const [nom, denom] = - position.data.price.map((n) => new BN(n.toString())) ?? [] - const price = nom.div(denom) - const positionPrice = price.times(BN_10.pow(18)) - - const params: Parameters = [ - omnipoolBalance.balance.toString(), - omnipoolAsset.data.hubReserve.toString(), - omnipoolAsset.data.shares.toString(), - position.data.amount.toString(), - position.data.shares.toString(), - positionPrice.toFixed(0), - position.data.shares.toString(), - "0", // fee zero - ] - - lernaOutResult = calculate_liquidity_lrna_out.apply(this, params) - liquidityOutResult = calculate_liquidity_out.apply(this, params) - - const lrnaDp = BN_10.pow(lrnaMeta.decimals) - const lrna = - lernaOutResult !== "-1" - ? new BN(lernaOutResult).div(lrnaDp) - : BN_NAN - - const valueDp = BN_10.pow(meta.decimals) - const value = - liquidityOutResult !== "-1" - ? new BN(liquidityOutResult).div(valueDp) - : BN_NAN - - let valueDisplay = BN_NAN - - if (liquidityOutResult !== "-1" && spotPrice) { - valueDisplay = value.times(spotPrice.spotPrice) - - if (lrna.gt(0)) { - valueDisplay = !lrnaSp - ? BN_NAN - : valueDisplay.plus(lrna.times(lrnaSp.data.spotPrice)) - } - } - - const providedAmount = normalizeBigNumber( - position.data.amount, - ).shiftedBy(-1 * meta.decimals) - const providedAmountDisplay = spotPrice?.spotPrice - ? providedAmount.times(spotPrice.spotPrice) - : BN_NAN + const { + lrna, + value, + valueDisplay, + providedAmount, + providedAmountDisplay, + } = calculatePositionLiquidity({ + position: position.data, + omnipoolBalance: omnipoolBalance.balance, + omnipoolHubReserve: omnipoolAsset.data.hubReserve, + omnipoolShares: omnipoolAsset.data.shares, + lrnaSpotPrice: lrnaSp.data.spotPrice, + valueSpotPrice: spotPrice.spotPrice, + lrnaDecimals: lrnaMeta.decimals, + assetDecimals: meta.decimals, + }) const index = position.data?.assetId.toString() @@ -203,7 +150,7 @@ export const useAllUserDepositShare = ({ } export const useDepositShare = (poolId: u32 | string, depositNftId: string) => { - const deposits = useAllUserDepositShare() + const deposits = useAllOmnipoolDeposits() const deposit = deposits.data[poolId.toString()]?.find( (deposit) => deposit.depositId === depositNftId, @@ -211,3 +158,53 @@ export const useDepositShare = (poolId: u32 | string, depositNftId: string) => { return { data: deposit, isLoading: deposits.isLoading } } + +export const useAllOmnipoolDeposits = (address?: string) => { + const { omnipoolDeposits } = useUserDeposits(address) + + return useOmnipoolDepositValues(omnipoolDeposits.map((deposit) => deposit.id)) +} + +export const useAllXYKDeposits = (address?: string) => { + const { xykDeposits } = useUserDeposits(address) + + return useXYKDepositValues(xykDeposits) +} + +export const useAllFarmDeposits = (address?: string) => { + const omnipoolDepositValues = useAllOmnipoolDeposits(address) + const xykDepositValues = useAllXYKDeposits(address) + + const isLoading = + omnipoolDepositValues.isLoading || xykDepositValues.isLoading + + return { + isLoading, + omnipool: omnipoolDepositValues.data, + xyk: xykDepositValues.data, + } +} + +export const useFarmDepositsTotal = (address?: string) => { + const { isLoading, omnipool, xyk } = useAllFarmDeposits(address) + + const total = useMemo(() => { + let poolsTotal = BN_0 + + for (const poolId in omnipool) { + const poolTotal = omnipool[poolId].reduce((memo, share) => { + return memo.plus(share.valueDisplay) + }, BN_0) + poolsTotal = poolsTotal.plus(poolTotal) + } + + const xykTotal = xyk.reduce((memo, deposit) => { + if (deposit.amountUSD) return memo.plus(deposit.amountUSD) + return memo + }, BN_0) + + return poolsTotal.plus(xykTotal) + }, [omnipool, xyk]) + + return { isLoading: isLoading, value: total } +} diff --git a/src/sections/pools/header/MyFarmsTotal.tsx b/src/sections/pools/header/MyFarmsTotal.tsx index d9cec6ded..b3c984ce8 100644 --- a/src/sections/pools/header/MyFarmsTotal.tsx +++ b/src/sections/pools/header/MyFarmsTotal.tsx @@ -1,23 +1,8 @@ -import { useMemo } from "react" -import { useAllUserDepositShare } from "sections/pools/farms/position/FarmingPosition.utils" +import { useFarmDepositsTotal } from "sections/pools/farms/position/FarmingPosition.utils" import { HeaderTotalData } from "./PoolsHeaderTotal" -import { BN_0 } from "utils/constants" export const MyFarmsTotal = () => { - const miningPositions = useAllUserDepositShare() + const total = useFarmDepositsTotal() - const totalFarms = useMemo(() => { - let calculatedShares = BN_0 - for (const poolId in miningPositions.data) { - const poolTotal = miningPositions.data[poolId].reduce((memo, share) => { - return memo.plus(share.valueDisplay) - }, BN_0) - calculatedShares = calculatedShares.plus(poolTotal) - } - return calculatedShares - }, [miningPositions.data]) - - return ( - - ) + return } diff --git a/src/sections/pools/header/MyLiquidityTotal.tsx b/src/sections/pools/header/MyLiquidityTotal.tsx index 22c1d92af..349f5ef10 100644 --- a/src/sections/pools/header/MyLiquidityTotal.tsx +++ b/src/sections/pools/header/MyLiquidityTotal.tsx @@ -2,7 +2,7 @@ import { useMemo } from "react" import { useOmnipoolPositionsData } from "sections/wallet/assets/hydraPositions/data/WalletAssetsHydraPositionsData.utils" import { BN_0 } from "utils/constants" import { HeaderTotalData } from "./PoolsHeaderTotal" -import { useAllUserDepositShare } from "sections/pools/farms/position/FarmingPosition.utils" +import { useFarmDepositsTotal } from "sections/pools/farms/position/FarmingPosition.utils" import { useMyStablePoolaTotal } from "./StablePoolsTotal" import { useXYKPools } from "sections/pools/PoolsPage.utils" import { Text } from "components/Typography/Text/Text" @@ -12,7 +12,7 @@ import { Trans, useTranslation } from "react-i18next" export const MyLiquidityTotal = () => { const { t } = useTranslation() const omnipoolPositions = useOmnipoolPositionsData() - const miningPositions = useAllUserDepositShare() + const totalFarms = useFarmDepositsTotal() const stablePoolTotal = useMyStablePoolaTotal() const xylPools = useXYKPools(true) @@ -35,34 +35,24 @@ export const MyLiquidityTotal = () => { }, BN_0) }, [omnipoolPositions.data]) - const totalFarms = useMemo(() => { - let calculatedShares = BN_0 - for (const poolId in miningPositions.data) { - const poolTotal = miningPositions.data[poolId].reduce((memo, share) => { - return memo.plus(share.valueDisplay) - }, BN_0) - calculatedShares = calculatedShares.plus(poolTotal) - } - return calculatedShares - }, [miningPositions.data]) - const total = xykTotal .plus(totalOmnipool) .plus(stablePoolTotal.value) - .plus(totalFarms) + .plus(totalFarms.value) return ( - + } diff --git a/src/sections/pools/navigation/Navigation.tsx b/src/sections/pools/navigation/Navigation.tsx index d6b21b692..df38bde1d 100644 --- a/src/sections/pools/navigation/Navigation.tsx +++ b/src/sections/pools/navigation/Navigation.tsx @@ -5,7 +5,6 @@ import AllPools from "assets/icons/AllPools.svg?react" import OmniStablepools from "assets/icons/Omnipool&Stablepool.svg?react" import IsolatedPools from "assets/icons/IsolatedPools.svg?react" import { SSeparator } from "components/Separator/Separator.styled" -import { useAccountNFTPositions } from "sections/pools/PoolsPage.utils" import { useRpcProvider } from "providers/rpcProvider" import { useTranslation } from "react-i18next" import { useTokensBalances } from "api/balances" @@ -17,6 +16,7 @@ import { import { BackSubHeader } from "components/Layout/Header/BackSubHeader/BackSubHeader" import { useLocation } from "@tanstack/react-location" import { t } from "i18next" +import { useAccountNFTPositions } from "api/deposits" const routeMap = new Map([ [LINKS.allPools, t("liquidity.navigation.allPools")], diff --git a/src/sections/pools/pool/myPositions/MyPositions.tsx b/src/sections/pools/pool/myPositions/MyPositions.tsx index 20d737ff4..6a2e6875d 100644 --- a/src/sections/pools/pool/myPositions/MyPositions.tsx +++ b/src/sections/pools/pool/myPositions/MyPositions.tsx @@ -7,7 +7,7 @@ import { useMemo } from "react" import { useTranslation } from "react-i18next" import { TPoolFullData, TXYKPoolFullData } from "sections/pools/PoolsPage.utils" import { FarmingPositionWrapper } from "sections/pools/farms/FarmingPositionWrapper" -import { useAllUserDepositShare } from "sections/pools/farms/position/FarmingPosition.utils" +import { useAllOmnipoolDeposits } from "sections/pools/farms/position/FarmingPosition.utils" import { LiquidityPositionWrapper } from "sections/pools/pool/positions/LiquidityPositionWrapper" import { XYKPosition } from "sections/pools/pool/xykPosition/XYKPosition" import { StablepoolPosition } from "sections/pools/stablepool/positions/StablepoolPosition" @@ -22,7 +22,7 @@ export const MyPositions = ({ pool }: { pool: TPoolFullData }) => { const meta = assets.getAsset(pool.id) const queryClient = useQueryClient() - const miningPositions = useAllUserDepositShare() + const miningPositions = useAllOmnipoolDeposits() const stablepoolBalance = useTokenBalance( pool.isStablePool ? pool.id : undefined, diff --git a/src/sections/wallet/assets/WalletAssets.utils.ts b/src/sections/wallet/assets/WalletAssets.utils.ts index 3a6f91299..2e0511669 100644 --- a/src/sections/wallet/assets/WalletAssets.utils.ts +++ b/src/sections/wallet/assets/WalletAssets.utils.ts @@ -4,7 +4,7 @@ import BN from "bignumber.js" import { useWarningsStore } from "components/WarningMessage/WarningMessage.utils" import { useRpcProvider } from "providers/rpcProvider" import { useEffect, useMemo } from "react" -import { useAllUserDepositShare } from "sections/pools/farms/position/FarmingPosition.utils" +import { useFarmDepositsTotal } from "sections/pools/farms/position/FarmingPosition.utils" import { useOmnipoolPositionsData } from "sections/wallet/assets/hydraPositions/data/WalletAssetsHydraPositionsData.utils" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { NATIVE_ASSET_ID } from "utils/api" @@ -55,7 +55,7 @@ export const useWalletAssetsTotals = ({ const { account } = useAccount() const assets = useAssetsData({ isAllAssets: false, address }) const lpPositions = useOmnipoolPositionsData({ address }) - const farmsPositions = useAllUserDepositShare({ address }) + const farmsTotal = useFarmDepositsTotal(address) const shareTokenIds = shareTokens.map((shareToken) => shareToken.id) const shareTokenBalances = useTokensBalances(shareTokenIds, account?.address) @@ -91,17 +91,6 @@ export const useWalletAssetsTotals = ({ }, BN_0) }, [assets]) - const farmsTotal = useMemo(() => { - let calculatedShares = BN_0 - for (const poolId in farmsPositions.data) { - const poolTotal = farmsPositions.data[poolId].reduce((memo, share) => { - return memo.plus(share.valueDisplay) - }, BN_0) - calculatedShares = calculatedShares.plus(poolTotal) - } - return calculatedShares - }, [farmsPositions]) - const lpTotal = useMemo(() => { if (!lpPositions.data) return BN_0 @@ -134,13 +123,16 @@ export const useWalletAssetsTotals = ({ }, BN_0) }, [getAsset, shareTokenBalances, spotPrices.data]) - const balanceTotal = assetsTotal.plus(farmsTotal).plus(lpTotal).plus(xykTotal) + const balanceTotal = assetsTotal + .plus(farmsTotal.value) + .plus(lpTotal) + .plus(xykTotal) const isLoading = - assets.isLoading || lpPositions.isLoading || farmsPositions.isLoading + assets.isLoading || lpPositions.isLoading || farmsTotal.isLoading return { assetsTotal, - farmsTotal, + farmsTotal: farmsTotal.value, lpTotal: lpTotal.plus(xykTotal), balanceTotal, isLoading, diff --git a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx index dbb27d505..9db659828 100644 --- a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx +++ b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx @@ -112,7 +112,7 @@ export const WalletFarmingPositions = ({ data }: Props) => { - {!isDesktop && ( + {!isDesktop && row && ( setRow(undefined)} diff --git a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx index bf0751474..d4e94db57 100644 --- a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx +++ b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx @@ -15,7 +15,7 @@ import { isAfter } from "date-fns" import { useMemo, useState } from "react" import { useTranslation } from "react-i18next" import { useMedia } from "react-use" -import { useAllUserDepositShare } from "sections/pools/farms/position/FarmingPosition.utils" +import { useAllOmnipoolDeposits } from "sections/pools/farms/position/FarmingPosition.utils" import { theme } from "theme" import { getFloatingPointAmount } from "utils/balance" import { getEnteredDate } from "utils/block" @@ -23,14 +23,17 @@ import { BN_0, BN_NAN } from "utils/constants" import { DisplayValue } from "components/DisplayValue/DisplayValue" import { AssetTableName } from "components/AssetTableName/AssetTableName" import { useRpcProvider } from "providers/rpcProvider" -import { arraySearch } from "utils/helpers" +import { arraySearch, isNotNil } from "utils/helpers" import { WalletAssetsHydraPositionsDetails } from "sections/wallet/assets/hydraPositions/details/WalletAssetsHydraPositionsDetails" import { ButtonTransparent } from "components/Button/Button" import { Icon } from "components/Icon/Icon" import ChevronRightIcon from "assets/icons/ChevronRight.svg?react" +import { useXYKDepositValues } from "sections/pools/PoolsPage.utils" +import { scaleHuman } from "utils/balance" export const useFarmingPositionsTable = (data: FarmingPositionsTableData[]) => { const { t } = useTranslation() + const { assets } = useRpcProvider() const { accessor } = createColumnHelper() const [sorting, onSortingChange] = useState([]) @@ -71,27 +74,37 @@ export const useFarmingPositionsTable = (data: FarmingPositionsTableData[]) => { id: "shares", header: t("wallet.assets.farmingPositions.header.initial"), sortingFn: (a, b) => (a.original.shares.gt(b.original.shares) ? 1 : -1), - cell: ({ row }) => ( - <> + cell: ({ row }) => { + const meta = assets.getAsset(row.original.assetId) + return isXYKPosition(row.original.position) ? ( - {t("value.token", { - value: row.original.position.providedAmount, - })} + - - ( - - {children} - - )} - > - + + {t("value.token", { + value: scaleHuman( + row.original.position.providedAmount, + meta.decimals, + ), + })} + + - - - ), + wrapper={(children) => ( + + {children} + + )} + > + + + + ) + }, }), accessor("position", { id: "position", @@ -100,32 +113,38 @@ export const useFarmingPositionsTable = (data: FarmingPositionsTableData[]) => { a.original.position.valueDisplay.gt(b.original.position.valueDisplay) ? 1 : -1, - cell: ({ row }) => ( -
- - {!isDesktop && ( - - } - /> - - )} -
- ), + cell: ({ row }) => { + const position = row.original.position + const isXYK = isXYKPosition(position) + + return ( +
+ + {!isDesktop && ( + + } + /> + + )} +
+ ) + }, }), ], @@ -149,8 +168,9 @@ export const useFarmingPositionsData = ({ search?: string } = {}) => { const { assets } = useRpcProvider() - const { omnipoolDeposits } = useUserDeposits() - const accountDepositsShare = useAllUserDepositShare() + const { omnipoolDeposits, xykDeposits } = useUserDeposits() + const xykDepositValues = useXYKDepositValues(xykDeposits) + const accountDepositsShare = useAllOmnipoolDeposits() const bestNumber = useBestNumber() @@ -161,11 +181,19 @@ export const useFarmingPositionsData = ({ if (!omnipoolDeposits || !accountDepositsShare.data || !bestNumber.data) return [] - const rows: FarmingPositionsTableData[] = omnipoolDeposits + const rows = [...omnipoolDeposits, ...xykDeposits] .map((deposit) => { - const id = deposit.id.toString() - const assetId = deposit.data.ammPoolId.toString() - const meta = assets.getAsset(assetId) + const depositId = deposit.id + const isXyk = deposit.isXyk + const poolId = deposit.data.ammPoolId.toString() + + const meta = isXyk + ? assets.getShareTokenByAddress(poolId) + : assets.getAsset(poolId) + + if (!meta) return undefined + + const { symbol, decimals, name, id } = meta const latestEnteredAtBlock = deposit.data.yieldFarmEntries.reduce( (acc, curr) => acc.lt(curr.enteredAt.toBigNumber()) @@ -174,54 +202,103 @@ export const useFarmingPositionsData = ({ BN_0, ) - const symbol = meta.symbol - const name = meta.name const date = getEnteredDate( latestEnteredAtBlock, bestNumber.data.relaychainBlockNumber.toBigNumber(), ) const shares = getFloatingPointAmount( deposit.data.shares.toBigNumber(), - meta.decimals, + decimals, ) - const position = accountDepositsShare.data[assetId]?.find( - (d) => d.depositId?.toString() === deposit.id.toString(), - ) ?? { - symbol, - value: BN_NAN, - valueDisplay: BN_NAN, - lrna: BN_NAN, - amount: BN_NAN, - providedAmount: BN_NAN, - providedAmountDisplay: BN_NAN, + + let position + if (isXyk) { + const values = xykDepositValues.data.find( + (value) => value.assetId === id, + ) + + if (values?.amountUSD) { + const { assetA, assetB, amountUSD } = values + + position = { + balances: [ + { + amount: assetA.amount, + symbol: assetA.symbol, + }, + { + amount: assetB.amount, + symbol: assetB.symbol, + }, + ], + valueDisplay: amountUSD, + } + } else { + position = { + valueDisplay: BN_NAN, + } + } + } else { + position = accountDepositsShare.data[poolId]?.find( + (d) => d.depositId?.toString() === deposit.id.toString(), + ) ?? { + symbol, + value: BN_NAN, + valueDisplay: BN_NAN, + lrna: BN_NAN, + amount: BN_NAN, + providedAmount: BN_NAN, + providedAmountDisplay: BN_NAN, + } } return { - id, + id: depositId, symbol, name, date, shares, position, - assetId, + assetId: id, } }) + .filter(isNotNil) .sort((a, b) => b.position.valueDisplay.minus(a.position.valueDisplay).toNumber(), ) return search ? arraySearch(rows, search, ["symbol", "name"]) : rows }, [ + omnipoolDeposits, accountDepositsShare.data, bestNumber.data, - omnipoolDeposits, + xykDeposits, search, assets, + xykDepositValues, ]) return { data, isLoading } } +export const isXYKPosition = ( + position: XYKPosition | OmnipoolPosition, +): position is XYKPosition => !!(position as XYKPosition).balances + +type XYKPosition = { + valueDisplay: BN + balances: { amount: BN; symbol: string }[] +} + +type OmnipoolPosition = { + symbol: string + value: BN + valueDisplay: BN + lrna: BN + providedAmount: BN + providedAmountDisplay: BN +} + export type FarmingPositionsTableData = { id: string assetId: string @@ -229,12 +306,5 @@ export type FarmingPositionsTableData = { name: string date: Date shares: BN - position: { - symbol: string - value: BN - valueDisplay: BN - lrna: BN - providedAmount: BN - providedAmountDisplay: BN - } + position: XYKPosition | OmnipoolPosition } diff --git a/src/sections/wallet/assets/farmingPositions/details/FarmingPositionsDetailsMob.tsx b/src/sections/wallet/assets/farmingPositions/details/FarmingPositionsDetailsMob.tsx index 76e0d0470..6b95a47bd 100644 --- a/src/sections/wallet/assets/farmingPositions/details/FarmingPositionsDetailsMob.tsx +++ b/src/sections/wallet/assets/farmingPositions/details/FarmingPositionsDetailsMob.tsx @@ -9,43 +9,37 @@ import { SActionButtonsContainer } from "sections/wallet/assets/table/actions/Wa import { useRpcProvider } from "providers/rpcProvider" import { useSpotPrice } from "api/spotPrice" import { BN_0, BN_1 } from "utils/constants" -import { FarmingPositionsTableData } from "sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils" +import { + FarmingPositionsTableData, + isXYKPosition, +} from "sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils" type Props = { - row?: FarmingPositionsTableData + row: FarmingPositionsTableData onClose: () => void } export const FarmingPositionsDetailsMob = ({ row, onClose }: Props) => { const { t } = useTranslation() - const { assets } = useRpcProvider() - const meta = row?.assetId ? assets.getAsset(row.assetId) : undefined + const meta = assets.getAsset(row.assetId) - const lrnaSpotPrice = useSpotPrice(assets.getAsset("1").id, row?.assetId) + const lrnaSpotPrice = useSpotPrice(assets.getAsset("1").id, row.assetId) - const lrnaPositionPrice = - row?.position.lrna?.multipliedBy(lrnaSpotPrice.data?.spotPrice ?? BN_1) ?? - BN_0 + const position = row.position + const isXYK = isXYKPosition(position) - if (!row) return null + const lrnaPositionPrice = isXYK + ? BN_0 + : position.lrna.multipliedBy(lrnaSpotPrice.data?.spotPrice ?? BN_1) - const { - symbol, - date, - position: { - lrna, - providedAmount: amount, - providedAmountDisplay, - value, - valueDisplay, - }, - } = row + const { symbol, date } = row - const tKey = lrna?.gt(0) - ? "wallet.assets.hydraPositions.data.valueLrna" - : "wallet.assets.hydraPositions.data.value" + const tKey = + !isXYK && position.lrna.gt(0) + ? "wallet.assets.hydraPositions.data.valueLrna" + : "wallet.assets.hydraPositions.data.value" return ( @@ -63,13 +57,22 @@ export const FarmingPositionsDetailsMob = ({ row, onClose }: Props) => { - {t("value.tokenWithSymbol", { - value: lrnaPositionPrice.plus(value ?? BN_0), - symbol: meta?.symbol, - })} + {isXYK + ? position.balances + .map((balance) => + t("value.tokenWithSymbol", { + value: balance.amount, + symbol: balance.symbol, + }), + ) + .join(" | ") + : t("value.tokenWithSymbol", { + value: lrnaPositionPrice.plus(position.value), + symbol: meta?.symbol, + })} - {lrnaPositionPrice.gt(0) && ( + {!isXYK && lrnaPositionPrice.gt(0) && ( { @@ -97,24 +100,31 @@ export const FarmingPositionsDetailsMob = ({ row, onClose }: Props) => { fw={500} css={{ color: `rgba(${theme.rgbColors.paleBlue}, 0.6)` }} > - +
-
- - {t("wallet.assets.hydraPositions.header.providedAmount")} - - - {t("value.tokenWithSymbol", { value: amount, symbol })} - - - - -
+ {!isXYK && ( + <> +
+ + {t("wallet.assets.hydraPositions.header.providedAmount")} + + + {t("value.tokenWithSymbol", { + value: position.providedAmount, + symbol, + })} + + + + +
- + + + )}
diff --git a/src/sections/wallet/assets/hydraPositions/WalletAssetsHydraPositions.utils.tsx b/src/sections/wallet/assets/hydraPositions/WalletAssetsHydraPositions.utils.tsx index c3b7c3d93..6626114a2 100644 --- a/src/sections/wallet/assets/hydraPositions/WalletAssetsHydraPositions.utils.tsx +++ b/src/sections/wallet/assets/hydraPositions/WalletAssetsHydraPositions.utils.tsx @@ -21,7 +21,6 @@ import { isXYKPosition, TXYKPosition, } from "./data/WalletAssetsHydraPositionsData.utils" -import { DisplayValue } from "components/DisplayValue/DisplayValue" export const useHydraPositionsTable = ( data: (HydraPositionsTableData | TXYKPosition)[], @@ -82,37 +81,16 @@ export const useHydraPositionsTable = ( textAlign: "center", }} > - {isXYKPosition(row.original) ? ( -
-
- - {row.original.balances - ?.map((balance) => - t("value.tokenWithSymbol", { - value: balance.balanceHuman, - symbol: balance.symbol, - }), - ) - .join(" | ")} - -
- - - -
- ) : ( - - )} + + {!isDesktop && ( { .multipliedBy(totalIssuance?.myPoolShare ?? 1) .div(100) - return { balanceHuman, symbol: balanceMeta.symbol } + return { amount: balanceHuman, symbol: balanceMeta.symbol } }) ?? [] if (meta.assets.includes(assets.native.id)) { @@ -196,9 +196,12 @@ export const useXykPositionsData = ({ search }: { search?: string } = {}) => { // order of the HDX in a share token pair if (meta.assets[0] === assets.native.id) { - balances.unshift({ balanceHuman, symbol: assets.native.symbol }) + balances.unshift({ + amount: balanceHuman, + symbol: assets.native.symbol, + }) } else { - balances.push({ balanceHuman, symbol: assets.native.symbol }) + balances.push({ amount: balanceHuman, symbol: assets.native.symbol }) } } diff --git a/src/sections/wallet/assets/hydraPositions/details/WalletAssetsHydraPositionsDetails.tsx b/src/sections/wallet/assets/hydraPositions/details/WalletAssetsHydraPositionsDetails.tsx index 9053d1dc9..19c593f0a 100644 --- a/src/sections/wallet/assets/hydraPositions/details/WalletAssetsHydraPositionsDetails.tsx +++ b/src/sections/wallet/assets/hydraPositions/details/WalletAssetsHydraPositionsDetails.tsx @@ -9,9 +9,12 @@ import { useRpcProvider } from "providers/rpcProvider" import { useSpotPrice } from "api/spotPrice" import { BN_0, BN_1 } from "utils/constants" +type PairAsset = { amount: BN; symbol: string } + type Props = { assetId: string - amount: BN + amount?: BN + amountPair?: PairAsset[] lrna?: BN amountDisplay?: BN } @@ -20,38 +23,38 @@ export const WalletAssetsHydraPositionsDetails = ({ amount, lrna, amountDisplay, + amountPair, assetId, }: Props) => { - const isDesktop = useMedia(theme.viewport.gte.sm) - const { t } = useTranslation() const { assets } = useRpcProvider() - - const meta = assetId ? assets.getAsset(assetId.toString()) : undefined - - const lrnaSpotPrice = useSpotPrice(assets.getAsset("1").id, assetId) - - const lrnaPositionPrice = - lrna?.multipliedBy(lrnaSpotPrice.data?.spotPrice ?? BN_1) ?? BN_0 + const meta = assets.getAsset(assetId.toString()) return (
-
+ {amountPair ? ( +
+ + {amountPair + .map((balance) => + t("value.tokenWithSymbol", { + value: balance.amount, + symbol: balance.symbol, + }), + ) + .join(" | ")} + +
+ ) : lrna && !lrna.isZero() ? ( + + ) : ( {t("value.tokenWithSymbol", { - value: lrnaPositionPrice.plus(amount ?? BN_0), + value: amount, symbol: meta?.symbol, })} - - {isDesktop && ( - - )} -
+ )} {amountDisplay && ( ) } + +const LrnaValue = ({ + assetId, + lrna, + amount, +}: { + assetId: string + lrna: BN + amount?: BN +}) => { + const isDesktop = useMedia(theme.viewport.gte.sm) + const { t } = useTranslation() + const { assets } = useRpcProvider() + + const meta = assetId ? assets.getAsset(assetId.toString()) : undefined + const lrnaSpotPrice = useSpotPrice(assets.getAsset("1").id, assetId) + + const lrnaPositionPrice = + lrna?.multipliedBy(lrnaSpotPrice.data?.spotPrice ?? BN_1) ?? BN_0 + return ( +
+ + {t("value.tokenWithSymbol", { + value: lrnaPositionPrice.plus(amount ?? BN_0), + symbol: meta?.symbol, + })} + + + {isDesktop && ( + + )} +
+ ) +} diff --git a/src/utils/omnipool.ts b/src/utils/omnipool.ts index ea165d336..6b85c5773 100644 --- a/src/utils/omnipool.ts +++ b/src/utils/omnipool.ts @@ -3,7 +3,6 @@ import { calculate_liquidity_out, } from "@galacticcouncil/math-omnipool" import { u128 } from "@polkadot/types-codec" -import { PalletOmnipoolPosition } from "@polkadot/types/lookup" import { OmnipoolPosition } from "api/omnipool" import BN from "bignumber.js" import { BN_10, BN_NAN } from "utils/constants" @@ -18,7 +17,7 @@ export const calculatePositionLiquidity = ({ lrnaDecimals, assetDecimals, }: { - position: PalletOmnipoolPosition | OmnipoolPosition + position: OmnipoolPosition omnipoolBalance?: BN omnipoolHubReserve?: u128 omnipoolShares?: u128 From a68c183a185e28a7b56af781a5f98275f0ca25d8 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Mon, 15 Apr 2024 21:44:03 +0200 Subject: [PATCH 022/103] fix lint --- .../position/redeposit/RedepositFarms.tsx | 34 +------------------ .../RemoveLiquidity/RemoveLiquidity.utils.tsx | 2 +- src/sections/pools/table/PoolsTable.utils.tsx | 2 +- .../omnipoolAsset/stats/AssetStats.tsx | 2 +- .../OmnipoolAssetsTableWrapper.utils.tsx | 2 +- .../otc/orders/OtcOrdersData.utils.ts | 2 +- .../WalletFarmingPositions.tsx | 8 ++--- .../WalletFarmingPositions.utils.tsx | 30 +++++++--------- .../details/FarmingPositionsDetailsMob.tsx | 4 +-- .../details/HydraPositionsDetailsMob.tsx | 2 +- src/sections/web3-connect/wallets/index.ts | 7 +--- src/utils/omnipool.ts | 2 +- 12 files changed, 27 insertions(+), 70 deletions(-) diff --git a/src/sections/pools/farms/position/redeposit/RedepositFarms.tsx b/src/sections/pools/farms/position/redeposit/RedepositFarms.tsx index eb18930ed..b2d0aeb38 100644 --- a/src/sections/pools/farms/position/redeposit/RedepositFarms.tsx +++ b/src/sections/pools/farms/position/redeposit/RedepositFarms.tsx @@ -1,13 +1,9 @@ import { Text } from "components/Typography/Text/Text" import { SContainer, SJoinButton } from "./RedepositFarms.styled" import { Trans, useTranslation } from "react-i18next" -import { useFarmRedepositMutation } from "utils/farms/redeposit" import { JoinFarmModal } from "sections/pools/farms/modals/join/JoinFarmsModal" -import { TOAST_MESSAGES } from "state/toasts" -import { ToastMessage } from "state/store" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { TMiningNftPosition } from "sections/pools/PoolsPage.utils" -import { useRpcProvider } from "providers/rpcProvider" import { GlobalFarmRowMulti } from "sections/pools/farms/components/globalFarm/GlobalFarmRowMulti" import { useState } from "react" import { useFarms } from "api/farms" @@ -19,12 +15,10 @@ type RedepositFarmsProps = { export const RedepositFarms = ({ depositNft, poolId }: RedepositFarmsProps) => { const { t } = useTranslation() - const { assets } = useRpcProvider() const { account } = useAccount() const [joinFarm, setJoinFarm] = useState(false) const farms = useFarms([poolId]) - const meta = assets.getAsset(poolId.toString()) let availableYieldFarms = farms.data?.filter( @@ -36,31 +30,6 @@ export const RedepositFarms = ({ depositNft, poolId }: RedepositFarmsProps) => { ), ) ?? [] - const toast = TOAST_MESSAGES.reduce((memo, type) => { - const msType = type === "onError" ? "onLoading" : type - memo[type] = ( - - - - - ) - return memo - }, {} as ToastMessage) - - const redeposit = useFarmRedepositMutation( - availableYieldFarms, - [depositNft], - toast, - () => setJoinFarm(false), - ) - if (!availableYieldFarms.length) return null return ( @@ -89,11 +58,10 @@ export const RedepositFarms = ({ depositNft, poolId }: RedepositFarmsProps) => { {joinFarm && ( setJoinFarm(false)} + onSuccess={() => null} isRedeposit /> )} diff --git a/src/sections/pools/modals/RemoveLiquidity/RemoveLiquidity.utils.tsx b/src/sections/pools/modals/RemoveLiquidity/RemoveLiquidity.utils.tsx index a7234bbde..030203a7a 100644 --- a/src/sections/pools/modals/RemoveLiquidity/RemoveLiquidity.utils.tsx +++ b/src/sections/pools/modals/RemoveLiquidity/RemoveLiquidity.utils.tsx @@ -86,7 +86,7 @@ export const useRemoveLiquidity = ( minlFeeQuery.data ) { const positionPrice = scale(position.price, "q") - const oraclePrice = oracle.data.oraclePrice + const oraclePrice = oracle.data.oraclePrice ?? BN_0 const minWithdrawalFee = minlFeeQuery.data const lrnaSpotPrice = calculate_lrna_spot_price( diff --git a/src/sections/pools/table/PoolsTable.utils.tsx b/src/sections/pools/table/PoolsTable.utils.tsx index 1fb84b070..bf2043f5e 100644 --- a/src/sections/pools/table/PoolsTable.utils.tsx +++ b/src/sections/pools/table/PoolsTable.utils.tsx @@ -258,7 +258,7 @@ const APY = ({ } = useRpcProvider() const farms = useFarms([assetId]) - if (isLoading || farms.isInitialLoading) return + if (isLoading || farms.isLoading) return if (farms.data?.length) return diff --git a/src/sections/stats/sections/omnipoolAsset/stats/AssetStats.tsx b/src/sections/stats/sections/omnipoolAsset/stats/AssetStats.tsx index 6cc03cbc8..1eb81f16f 100644 --- a/src/sections/stats/sections/omnipoolAsset/stats/AssetStats.tsx +++ b/src/sections/stats/sections/omnipoolAsset/stats/AssetStats.tsx @@ -62,7 +62,7 @@ const APYStatsCard = ({ value={ assetId === native.id ? "--" : t("value.percentage", { value: fee }) } - loading={loading || farms.isInitialLoading} + loading={loading || farms.isLoading} tooltip={t("stats.overview.table.assets.header.apy.desc")} /> ) diff --git a/src/sections/stats/sections/overview/components/OmnipoolAssetsTableWrapper/OmnipoolAssetsTableWrapper.utils.tsx b/src/sections/stats/sections/overview/components/OmnipoolAssetsTableWrapper/OmnipoolAssetsTableWrapper.utils.tsx index 22a97caff..76c32b1e6 100644 --- a/src/sections/stats/sections/overview/components/OmnipoolAssetsTableWrapper/OmnipoolAssetsTableWrapper.utils.tsx +++ b/src/sections/stats/sections/overview/components/OmnipoolAssetsTableWrapper/OmnipoolAssetsTableWrapper.utils.tsx @@ -69,7 +69,7 @@ const APY = ({ } = useRpcProvider() const farms = useFarms([assetId]) - if (isLoading || farms.isInitialLoading) return + if (isLoading || farms.isLoading) return if (farms.data?.length) return diff --git a/src/sections/trade/sections/otc/orders/OtcOrdersData.utils.ts b/src/sections/trade/sections/otc/orders/OtcOrdersData.utils.ts index 16ef54cb5..be6f0dea7 100644 --- a/src/sections/trade/sections/otc/orders/OtcOrdersData.utils.ts +++ b/src/sections/trade/sections/otc/orders/OtcOrdersData.utils.ts @@ -2,7 +2,7 @@ import { useMemo } from "react" import { useOrdersData, useOrdersState, getOrderStateValue } from "api/otc" import BN from "bignumber.js" import { useAssetPrices } from "utils/displayAsset" -import { calculateDiffToAvg, calculateDiffToRef } from "@galacticcouncil/sdk" +import { calculateDiffToRef } from "@galacticcouncil/sdk" export const useOrdersTableData = () => { const treasuryAddr = import.meta.env.VITE_TRSRY_ADDR diff --git a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx index 9db659828..6f2f6a7a0 100644 --- a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx +++ b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx @@ -12,7 +12,7 @@ import { Text } from "components/Typography/Text/Text" import { Fragment, useState } from "react" import { useTranslation } from "react-i18next" import { - FarmingPositionsTableData, + FarmingTablePosition, useFarmingPositionsTable, } from "./WalletFarmingPositions.utils" import { assetsTableStyles } from "sections/wallet/assets/table/WalletAssetsTable.styled" @@ -24,13 +24,11 @@ import { EmptyState } from "components/Table/EmptyState" import EmptyStateIcon from "assets/icons/FarmsEmpty.svg?react" import { LINKS } from "utils/navigation" -type Props = { data: FarmingPositionsTableData[] } +type Props = { data: FarmingTablePosition[] } export const WalletFarmingPositions = ({ data }: Props) => { const { t } = useTranslation() - const [row, setRow] = useState( - undefined, - ) + const [row, setRow] = useState(undefined) const table = useFarmingPositionsTable(data) diff --git a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx index d4e94db57..40ea7d048 100644 --- a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx +++ b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx @@ -19,7 +19,7 @@ import { useAllOmnipoolDeposits } from "sections/pools/farms/position/FarmingPos import { theme } from "theme" import { getFloatingPointAmount } from "utils/balance" import { getEnteredDate } from "utils/block" -import { BN_0, BN_NAN } from "utils/constants" +import { BN_0 } from "utils/constants" import { DisplayValue } from "components/DisplayValue/DisplayValue" import { AssetTableName } from "components/AssetTableName/AssetTableName" import { useRpcProvider } from "providers/rpcProvider" @@ -31,10 +31,10 @@ import ChevronRightIcon from "assets/icons/ChevronRight.svg?react" import { useXYKDepositValues } from "sections/pools/PoolsPage.utils" import { scaleHuman } from "utils/balance" -export const useFarmingPositionsTable = (data: FarmingPositionsTableData[]) => { +export const useFarmingPositionsTable = (data: FarmingTablePosition[]) => { const { t } = useTranslation() const { assets } = useRpcProvider() - const { accessor } = createColumnHelper() + const { accessor } = createColumnHelper() const [sorting, onSortingChange] = useState([]) const isDesktop = useMedia(theme.viewport.gte.sm) @@ -211,7 +211,7 @@ export const useFarmingPositionsData = ({ decimals, ) - let position + let position: XYKPosition | OmnipoolPosition if (isXyk) { const values = xykDepositValues.data.find( (value) => value.assetId === id, @@ -234,21 +234,17 @@ export const useFarmingPositionsData = ({ valueDisplay: amountUSD, } } else { - position = { - valueDisplay: BN_NAN, - } + return undefined } } else { - position = accountDepositsShare.data[poolId]?.find( + const omnipoolDeposit = accountDepositsShare.data[poolId]?.find( (d) => d.depositId?.toString() === deposit.id.toString(), - ) ?? { - symbol, - value: BN_NAN, - valueDisplay: BN_NAN, - lrna: BN_NAN, - amount: BN_NAN, - providedAmount: BN_NAN, - providedAmountDisplay: BN_NAN, + ) + + if (omnipoolDeposit) { + position = omnipoolDeposit + } else { + return undefined } } @@ -299,7 +295,7 @@ type OmnipoolPosition = { providedAmountDisplay: BN } -export type FarmingPositionsTableData = { +export type FarmingTablePosition = { id: string assetId: string symbol: string diff --git a/src/sections/wallet/assets/farmingPositions/details/FarmingPositionsDetailsMob.tsx b/src/sections/wallet/assets/farmingPositions/details/FarmingPositionsDetailsMob.tsx index 6b95a47bd..992fee2e3 100644 --- a/src/sections/wallet/assets/farmingPositions/details/FarmingPositionsDetailsMob.tsx +++ b/src/sections/wallet/assets/farmingPositions/details/FarmingPositionsDetailsMob.tsx @@ -10,12 +10,12 @@ import { useRpcProvider } from "providers/rpcProvider" import { useSpotPrice } from "api/spotPrice" import { BN_0, BN_1 } from "utils/constants" import { - FarmingPositionsTableData, + FarmingTablePosition, isXYKPosition, } from "sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils" type Props = { - row: FarmingPositionsTableData + row: FarmingTablePosition onClose: () => void } diff --git a/src/sections/wallet/assets/hydraPositions/details/HydraPositionsDetailsMob.tsx b/src/sections/wallet/assets/hydraPositions/details/HydraPositionsDetailsMob.tsx index 28481aad1..83225a583 100644 --- a/src/sections/wallet/assets/hydraPositions/details/HydraPositionsDetailsMob.tsx +++ b/src/sections/wallet/assets/hydraPositions/details/HydraPositionsDetailsMob.tsx @@ -40,7 +40,7 @@ export const HydraPositionsDetailsMob = ({ row, onClose }: Props) => { {row.balances ?.map((balance) => t("value.tokenWithSymbol", { - value: balance.balanceHuman, + value: balance.amount, symbol: balance.symbol, }), ) diff --git a/src/sections/web3-connect/wallets/index.ts b/src/sections/web3-connect/wallets/index.ts index 3e6036c38..5cbc0adb4 100644 --- a/src/sections/web3-connect/wallets/index.ts +++ b/src/sections/web3-connect/wallets/index.ts @@ -1,9 +1,4 @@ -import { - SubscriptionFn, - Wallet, - WalletAccount, - getWallets, -} from "@talismn/connect-wallets" +import { SubscriptionFn, Wallet, getWallets } from "@talismn/connect-wallets" import { ExternalWallet } from "./ExternalWallet" import { MetaMask } from "./MetaMask" diff --git a/src/utils/omnipool.ts b/src/utils/omnipool.ts index 6b85c5773..4df790b3a 100644 --- a/src/utils/omnipool.ts +++ b/src/utils/omnipool.ts @@ -17,7 +17,7 @@ export const calculatePositionLiquidity = ({ lrnaDecimals, assetDecimals, }: { - position: OmnipoolPosition + position: Omit omnipoolBalance?: BN omnipoolHubReserve?: u128 omnipoolShares?: u128 From 92064f8ade311193e55f133821581d60c7f143fb Mon Sep 17 00:00:00 2001 From: vkulinich Date: Mon, 15 Apr 2024 21:57:49 +0200 Subject: [PATCH 023/103] fix fullness --- src/api/farms.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/api/farms.ts b/src/api/farms.ts index 71d8cbbef..a003132d5 100644 --- a/src/api/farms.ts +++ b/src/api/farms.ts @@ -19,6 +19,7 @@ import { useIndexerUrl } from "./provider" import request, { gql } from "graphql-request" import { AccountId32 } from "@polkadot/types/interfaces" import { useMemo } from "react" +import { scale } from "utils/balance" const NEW_YIELD_FARMS_BLOCKS = (48 * 60 * 60) / PARACHAIN_BLOCK_TIME.toNumber() // 48 hours @@ -336,18 +337,10 @@ export const useFarmApr = (farm: { yieldFarm: PalletLiquidityMiningYieldFarmData poolId: string }) => { - //const { assets } = useRpcProvider() const bestNumber = useBestNumber() const rewardCurrency = farm.globalFarm.rewardCurrency.toString() const incentivizedAsset = farm.globalFarm.incentivizedAsset.toString() - //const isXYK = assets.getAsset(farm.poolId).isShareToken - - // const oraclePrice = useOraclePrice( - // isXYK ? undefined : rewardCurrency, - // incentivizedAsset, - // ) - const oraclePrice = useOraclePrice(rewardCurrency, incentivizedAsset) return useQueryReduce( @@ -440,7 +433,7 @@ const getOraclePrice = if (rewardCurrency === incentivizedAsset) return { id: { rewardCurrency, incentivizedAsset }, - oraclePrice: BN_1, + oraclePrice: scale(BN_1, "q"), } const res = await api.query.emaOracle.oracles( "omnipool", From 5837f1b4758e0e833ce5e9b7fed0c56a73fde478 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Mon, 15 Apr 2024 22:08:12 +0200 Subject: [PATCH 024/103] fix conflicts --- src/api/provider.ts | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/api/provider.ts b/src/api/provider.ts index 280886a7c..6aba664c5 100644 --- a/src/api/provider.ts +++ b/src/api/provider.ts @@ -100,20 +100,7 @@ export const useProviderData = (rpcUrl: string) => { QUERY_KEYS.provider(rpcUrl), async ({ queryKey: [_, url] }) => { const apiPool = SubstrateApis.getInstance() - const api = await apiPool.api(rpcUrl) - - api.registry.register({ - XykLMDeposit: { - shares: "u128", - ammPoolId: "AccountId", - yieldFarmEntries: "Vec", - }, - OmnipoolLMDeposit: { - shares: "u128", - ammPoolId: "u32", - yieldFarmEntries: "Vec", - }, - }) + const api = await apiPool.api(url) api.registry.register({ XykLMDeposit: { From 1949a89938e9128275ea03c8bd0871cd6453e9cf Mon Sep 17 00:00:00 2001 From: vkulinich Date: Tue, 16 Apr 2024 10:49:15 +0200 Subject: [PATCH 025/103] fix farm rewards value --- .../components/detailsCard/FarmDetailsCard.tsx | 13 +++++-------- .../modals/AddLiquidity/AddLiquidityFormXYK.tsx | 3 +++ src/sections/pools/pool/xykPosition/XYKPosition.tsx | 13 +++++++++++-- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/sections/pools/farms/components/detailsCard/FarmDetailsCard.tsx b/src/sections/pools/farms/components/detailsCard/FarmDetailsCard.tsx index c67873371..c548e82de 100644 --- a/src/sections/pools/farms/components/detailsCard/FarmDetailsCard.tsx +++ b/src/sections/pools/farms/components/detailsCard/FarmDetailsCard.tsx @@ -3,7 +3,7 @@ import { Text } from "components/Typography/Text/Text" import { Trans, useTranslation } from "react-i18next" import { SContainer, SIcon, SRow } from "./FarmDetailsCard.styled" import { FillBar } from "components/FillBar/FillBar" -import { getFloatingPointAmount } from "utils/balance" +import { scaleHuman } from "utils/balance" import { GradientText } from "components/Typography/GradientText/GradientText" import { addSeconds } from "date-fns" import ChevronDown from "assets/icons/ChevronDown.svg?react" @@ -120,11 +120,11 @@ export const FarmDetailsCard = ({ t={t} i18nKey="farms.details.card.distribution" tOptions={{ - distributed: getFloatingPointAmount( + distributed: scaleHuman( apr.data.distributedRewards, - 12, + asset.decimals, ), - max: getFloatingPointAmount(apr.data.maxRewards, 12), + max: scaleHuman(apr.data.maxRewards, asset.decimals), }} > @@ -155,10 +155,7 @@ export const FarmDetailsCard = ({ css={{ justifySelf: "end" }} > {t("farms.details.card.lockedShares.value", { - value: getFloatingPointAmount( - depositNft.data.shares, - assetMeta.decimals, - ), + value: scaleHuman(depositNft.data.shares, assetMeta.decimals), })} diff --git a/src/sections/pools/modals/AddLiquidity/AddLiquidityFormXYK.tsx b/src/sections/pools/modals/AddLiquidity/AddLiquidityFormXYK.tsx index 659de98be..bb7a6e083 100644 --- a/src/sections/pools/modals/AddLiquidity/AddLiquidityFormXYK.tsx +++ b/src/sections/pools/modals/AddLiquidity/AddLiquidityFormXYK.tsx @@ -169,6 +169,9 @@ export const AddLiquidityFormXYK = ({ pool, onClose }: Props) => { queryClient.refetchQueries( QUERY_KEYS.accountOmnipoolPositions(account?.address), ) + queryClient.refetchQueries( + QUERY_KEYS.tokenBalance(shareTokenMeta.id, account?.address), + ) }, onSubmitted: () => { onClose() diff --git a/src/sections/pools/pool/xykPosition/XYKPosition.tsx b/src/sections/pools/pool/xykPosition/XYKPosition.tsx index 25512027d..91fd92b33 100644 --- a/src/sections/pools/pool/xykPosition/XYKPosition.tsx +++ b/src/sections/pools/pool/xykPosition/XYKPosition.tsx @@ -19,12 +19,15 @@ import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { useMedia } from "react-use" import { theme } from "theme" import { JoinFarmsButton } from "sections/pools/farms/modals/join/JoinFarmsButton" +import { useQueryClient } from "@tanstack/react-query" +import { QUERY_KEYS } from "utils/queryKeys" export const XYKPosition = ({ pool }: { pool: TXYKPool }) => { const { t } = useTranslation() const { account } = useAccount() const { assets } = useRpcProvider() const isDesktop = useMedia(theme.viewport.gte.sm) + const queryClient = useQueryClient() const shareTokenMeta = assets.getAsset(pool.id) as TShareToken @@ -78,6 +81,12 @@ export const XYKPosition = ({ pool }: { pool: TXYKPool }) => { if (!pool.shareTokenIssuance || pool.shareTokenIssuance.myPoolShare?.isZero()) return null + const onSuccess = () => { + queryClient.refetchQueries( + QUERY_KEYS.tokenBalance(shareTokenMeta.id, account?.address), + ) + } + return (
@@ -109,10 +118,10 @@ export const XYKPosition = ({ pool }: { pool: TXYKPool }) => {
- null} /> + null} + onSuccess={onSuccess} />
From d15ac90ee9f19e97f8bec09eaf5214d98d9ab08a Mon Sep 17 00:00:00 2001 From: vkulinich Date: Tue, 16 Apr 2024 11:07:26 +0200 Subject: [PATCH 026/103] add farming positions amount --- src/sections/pools/PoolsPage.utils.ts | 18 +++++++++-- src/sections/pools/table/PoolsTable.utils.tsx | 32 +++++++++---------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/sections/pools/PoolsPage.utils.ts b/src/sections/pools/PoolsPage.utils.ts index fe0723190..0c454b40c 100644 --- a/src/sections/pools/PoolsPage.utils.ts +++ b/src/sections/pools/PoolsPage.utils.ts @@ -33,7 +33,10 @@ import { import { useShareOfPools } from "api/pools" import { TShareToken } from "api/assetDetails" import { useXYKPoolTradeVolumes } from "./pool/details/PoolDetails.utils" -import { useAllOmnipoolDeposits } from "./farms/position/FarmingPosition.utils" +import { + useAllOmnipoolDeposits, + useAllXYKDeposits, +} from "./farms/position/FarmingPosition.utils" import { useFee } from "api/stats" import { useTVL } from "api/stats" import { scaleHuman } from "utils/balance" @@ -420,6 +423,8 @@ export const useXYKPools = (withPositions?: boolean) => { : [], ) + const deposits = useAllXYKDeposits() + const queries = [ pools, shareTokens, @@ -469,6 +474,10 @@ export const useXYKPools = (withPositions?: boolean) => { (volume) => volume.poolAddress === pool.poolAddress, )?.volume ?? BN_NAN + const miningPositions = deposits.data.filter( + (deposit) => deposit.assetId === shareTokenMeta.id, + ) + return { id: shareTokenMeta.id, symbol: shareTokenMeta.symbol, @@ -483,11 +492,15 @@ export const useXYKPools = (withPositions?: boolean) => { shareTokenIssuance, volume, isVolumeLoading: volumes.isLoading, + miningPositions, } }) .filter(isNotNil) .filter((pool) => - withPositions ? pool.shareTokenIssuance?.myPoolShare?.gt(0) : true, + withPositions + ? pool.shareTokenIssuance?.myPoolShare?.gt(0) || + pool.miningPositions.length + : true, ) .sort((a, b) => b.tvlDisplay.minus(a.tvlDisplay).toNumber()) }, [ @@ -499,6 +512,7 @@ export const useXYKPools = (withPositions?: boolean) => { totalIssuances.data, withPositions, volumes, + deposits, ]) return { data, isInitialLoading } diff --git a/src/sections/pools/table/PoolsTable.utils.tsx b/src/sections/pools/table/PoolsTable.utils.tsx index bf2043f5e..9caaef561 100644 --- a/src/sections/pools/table/PoolsTable.utils.tsx +++ b/src/sections/pools/table/PoolsTable.utils.tsx @@ -147,19 +147,19 @@ const AddLiqduidityButton = ({ account?.address, ) - const isPosition = - userStablePoolBalance.data?.freeBalance.gt(0) || - (isXykPool ? pool.shareTokenIssuance?.myPoolShare?.gt(0) : pool.isPositions) - - const positionsAmount = isPosition - ? !isXykPool - ? BN(pool.omnipoolPositions.length) - .plus(pool.miningPositions.length) - .plus(userStablePoolBalance.data?.freeBalance.gt(0) ? 1 : 0) - : pool.shareTokenIssuance?.myPoolShare?.gt(0) - ? BN_1 - : undefined - : undefined + let positionsAmount: BN = BN_0 + + if (isXykPool) { + positionsAmount = BN(pool.miningPositions.length).plus( + pool.shareTokenIssuance?.myPoolShare?.gt(0) ? 1 : 0, + ) + } else { + positionsAmount = BN(pool.omnipoolPositions.length) + .plus(pool.miningPositions.length) + .plus(userStablePoolBalance.data?.freeBalance.gt(0) ? 1 : 0) + } + + const isPositions = positionsAmount.gt(0) const onClick = () => onRowSelect(pool.id) @@ -185,10 +185,10 @@ const AddLiqduidityButton = ({ }} onClick={onClick} > - {isPosition ? } size={12} /> : null} - {isPosition ? t("manage") : t("details")} + {isPositions ? } size={12} /> : null} + {isPositions ? t("manage") : t("details")} - {positionsAmount?.gt(0) && ( + {isPositions && ( Date: Tue, 16 Apr 2024 11:25:59 +0200 Subject: [PATCH 027/103] add locked in farms value --- src/sections/pools/PoolsPage.utils.ts | 9 +++++-- .../pools/pool/myPositions/MyPositions.tsx | 25 +++++++++++++++++++ .../pools/pool/xykPosition/XYKPosition.tsx | 3 --- .../WalletFarmingPositions.utils.tsx | 4 +-- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/sections/pools/PoolsPage.utils.ts b/src/sections/pools/PoolsPage.utils.ts index 0c454b40c..c66ff4677 100644 --- a/src/sections/pools/PoolsPage.utils.ts +++ b/src/sections/pools/PoolsPage.utils.ts @@ -633,7 +633,6 @@ export const useXYKDepositValues = (depositNfts: TMiningNftPosition[]) => { )?.totalShare if (!shareTokenIssuance) { - console.error("Could not calculate deposit balances") return { ...defaultValue, assetId: deposit.assetId } } @@ -661,7 +660,13 @@ export const useXYKDepositValues = (depositNfts: TMiningNftPosition[]) => { amount, } }) - return { assetA, assetB, amountUSD, assetId: deposit.assetId } + return { + assetA, + assetB, + amountUSD, + assetId: deposit.assetId, + depositId: deposit.depositNft.id, + } }) }, [ assets, diff --git a/src/sections/pools/pool/myPositions/MyPositions.tsx b/src/sections/pools/pool/myPositions/MyPositions.tsx index 6a2e6875d..ba73af92f 100644 --- a/src/sections/pools/pool/myPositions/MyPositions.tsx +++ b/src/sections/pools/pool/myPositions/MyPositions.tsx @@ -126,8 +126,33 @@ export const MyPositions = ({ pool }: { pool: TPoolFullData }) => { } export const MyXYKPositions = ({ pool }: { pool: TXYKPoolFullData }) => { + const { t } = useTranslation() + + const totalFarms = useMemo(() => { + return pool.miningPositions.reduce((memo, share) => { + return memo.plus(share.amountUSD ?? 0) + }, BN_0) + }, [pool.miningPositions]) + return (
+ + {t("liquidity.pool.positions.title")} + + {!totalFarms.isZero() && ( + <> + +
+ + {t("liquidity.pool.positions.farming")} + + + {t("value.usd", { amount: totalFarms })} + +
+ + + )}
diff --git a/src/sections/pools/pool/xykPosition/XYKPosition.tsx b/src/sections/pools/pool/xykPosition/XYKPosition.tsx index 91fd92b33..b1abc1f93 100644 --- a/src/sections/pools/pool/xykPosition/XYKPosition.tsx +++ b/src/sections/pools/pool/xykPosition/XYKPosition.tsx @@ -89,9 +89,6 @@ export const XYKPosition = ({ pool }: { pool: TXYKPool }) => { return (
- - {t("liquidity.pool.positions.title")} -
} /> diff --git a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx index 40ea7d048..952bdf70d 100644 --- a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx +++ b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.utils.tsx @@ -214,7 +214,7 @@ export const useFarmingPositionsData = ({ let position: XYKPosition | OmnipoolPosition if (isXyk) { const values = xykDepositValues.data.find( - (value) => value.assetId === id, + (value) => value.depositId === deposit.id, ) if (values?.amountUSD) { @@ -238,7 +238,7 @@ export const useFarmingPositionsData = ({ } } else { const omnipoolDeposit = accountDepositsShare.data[poolId]?.find( - (d) => d.depositId?.toString() === deposit.id.toString(), + (d) => d.depositId?.toString() === deposit.id, ) if (omnipoolDeposit) { From d427402eacfa00a4d9b28a11e7f33c2893d52b4c Mon Sep 17 00:00:00 2001 From: vkulinich Date: Tue, 16 Apr 2024 11:40:06 +0200 Subject: [PATCH 028/103] fix validation --- src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts | 3 +-- src/sections/pools/pool/xykPosition/XYKPosition.tsx | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts b/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts index e528d5cb6..6e63c5b70 100644 --- a/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts +++ b/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts @@ -8,7 +8,6 @@ import { Farm } from "api/farms" import { useMemo } from "react" import { scale, scaleHuman } from "utils/balance" import i18n from "i18next" -import BN from "bignumber.js" export const useZodSchema = (id: string, farms: Farm[]) => { const { account } = useAccount() @@ -22,7 +21,7 @@ export const useZodSchema = (id: string, farms: Farm[]) => { const minDeposit = farm.globalFarm.minDeposit.toBigNumber() return minDeposit.gt(acc) ? minDeposit : acc - }, BN(10000000)) + }, BN_0) }, [farms]) if (!balance) return undefined diff --git a/src/sections/pools/pool/xykPosition/XYKPosition.tsx b/src/sections/pools/pool/xykPosition/XYKPosition.tsx index b1abc1f93..2e9508f14 100644 --- a/src/sections/pools/pool/xykPosition/XYKPosition.tsx +++ b/src/sections/pools/pool/xykPosition/XYKPosition.tsx @@ -85,6 +85,9 @@ export const XYKPosition = ({ pool }: { pool: TXYKPool }) => { queryClient.refetchQueries( QUERY_KEYS.tokenBalance(shareTokenMeta.id, account?.address), ) + queryClient.refetchQueries( + QUERY_KEYS.accountOmnipoolPositions(account?.address), + ) } return ( From 98b1040adb3efbc7cb09284164e0a4fad64a6241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Tue, 16 Apr 2024 16:47:56 +0200 Subject: [PATCH 029/103] WalletConnect EVM XCM --- package.json | 6 +- .../transaction/ReviewTransactionForm.tsx | 2 +- .../web3-connect/signer/EthereumSigner.ts | 5 +- .../web3-connect/wallets/WalletConnect.ts | 42 +- src/sections/web3-connect/wallets/index.ts | 4 + src/utils/metamask.ts | 23 +- yarn.lock | 569 ++++++++++++++---- 7 files changed, 525 insertions(+), 126 deletions(-) diff --git a/package.json b/package.json index 47822f325..c6197756f 100644 --- a/package.json +++ b/package.json @@ -70,9 +70,9 @@ "@types/papaparse": "^5.3.14", "@types/uuid": "^8.3.4", "@walletconnect/modal": "^2.6.2", - "@walletconnect/sign-client": "2.8.0", - "@walletconnect/types": "^2.8.0", - "@walletconnect/universal-provider": "2.8.0", + "@walletconnect/sign-client": "2.12.2", + "@walletconnect/types": "^2.12.2", + "@walletconnect/universal-provider": "2.12.2", "bignumber.js": "^9.1.0", "color": "^4.2.3", "comlink": "^4.3.1", diff --git a/src/sections/transaction/ReviewTransactionForm.tsx b/src/sections/transaction/ReviewTransactionForm.tsx index ebdaf7dd0..a6ce65e30 100644 --- a/src/sections/transaction/ReviewTransactionForm.tsx +++ b/src/sections/transaction/ReviewTransactionForm.tsx @@ -1,5 +1,5 @@ import { TransactionResponse } from "@ethersproject/providers" -import { FC, useEffect, useState } from "react" +import { FC, useState } from "react" import { SubmittableExtrinsic } from "@polkadot/api/types" import { useMutation } from "@tanstack/react-query" import { Button } from "components/Button/Button" diff --git a/src/sections/web3-connect/signer/EthereumSigner.ts b/src/sections/web3-connect/signer/EthereumSigner.ts index 70ac69b08..7b3062bd6 100644 --- a/src/sections/web3-connect/signer/EthereumSigner.ts +++ b/src/sections/web3-connect/signer/EthereumSigner.ts @@ -8,8 +8,7 @@ import UniversalProvider from "@walletconnect/universal-provider/dist/types/Univ import { DISPATCH_ADDRESS } from "utils/evm" import { MetaMaskLikeProvider, - isMetaMask, - isMetaMaskLike, + isEthereumProvider, requestNetworkSwitch, } from "utils/metamask" @@ -55,7 +54,7 @@ export class EthereumSigner { const { chain, ...tx } = transaction const from = chain && evmChains[chain] ? chain : "hydradx" - if (isMetaMask(this.provider) || isMetaMaskLike(this.provider)) { + if (isEthereumProvider(this.provider)) { await requestNetworkSwitch(this.provider, { chain: from, onSwitch: () => { diff --git a/src/sections/web3-connect/wallets/WalletConnect.ts b/src/sections/web3-connect/wallets/WalletConnect.ts index 4ff2a10f5..f69975ada 100644 --- a/src/sections/web3-connect/wallets/WalletConnect.ts +++ b/src/sections/web3-connect/wallets/WalletConnect.ts @@ -16,14 +16,12 @@ import { PolkadotNamespaceChainId, PolkadotSigner, } from "sections/web3-connect/signer/PolkadotSigner" +import { noop } from "utils/helpers" const WC_LS_KEY_PREFIX = "wc@2" const WC_PROJECT_ID = import.meta.env.VITE_WC_PROJECT_ID as string const DOMAIN_URL = import.meta.env.VITE_DOMAIN_URL as string -const HDX_EVM_CHAIN_ID = import.meta.env.VITE_EVM_CHAIN_ID -const HDX_EVM_NAMESPACE_CHAIN_ID = `eip155:${HDX_EVM_CHAIN_ID}` - export const POLKADOT_CAIP_ID_MAP: Record = { hydradx: import.meta.env .VITE_HDX_CAIP_ID as string as PolkadotNamespaceChainId, @@ -55,20 +53,28 @@ const walletConnectParams = { }, } +const evmChainsArr = Object.values(evmChains) + const namespaces = { eip155: { - chains: [HDX_EVM_NAMESPACE_CHAIN_ID], + chains: evmChainsArr.map(({ id }) => `eip155:${id}`), methods: [ "eth_sendTransaction", "eth_signTransaction", "eth_sign", "personal_sign", "eth_signTypedData", + "wallet_switchEthereumChain", + "wallet_addEthereumChain", ], events: ["chainChanged", "accountsChanged"], - rpcMap: { - [HDX_EVM_CHAIN_ID]: evmChains["hydradx"].rpcUrls.default.http[0], - }, + rpcMap: evmChainsArr.reduce( + (prev, curr) => ({ + ...prev, + [curr.id]: curr.rpcUrls.default.http[0], + }), + {}, + ), }, polkadot: { methods: ["polkadot_signTransaction", "polkadot_signMessage"], @@ -96,18 +102,24 @@ export class WalletConnect implements Wallet { _session: SessionTypes.Struct | undefined _namespace: NamespaceConfig | undefined + onSessionDelete: () => void = noop + constructor({ onModalOpen, onModalClose, + onSesssionDelete, }: { onModalOpen?: ModalSubFn onModalClose?: ModalSubFn + onSesssionDelete?: () => void } = {}) { this._modal = new WalletConnectModal({ projectId: WC_PROJECT_ID, }) this.subscribeToModalEvents(onModalOpen, onModalClose) + + if (onSesssionDelete) this.onSessionDelete = onSesssionDelete } get extension() { @@ -152,8 +164,9 @@ export class WalletConnect implements Wallet { } this._extension = provider - provider.on("display_uri", this.onDisplayUri) - provider.on("session_update", this.onSessionUpdate) + provider.on("display_uri", this.handleDisplayUri) + provider.on("session_update", this.handleSessionUpdate) + provider.on("session_delete", this.handleSessionDelete) return provider } @@ -190,14 +203,19 @@ export class WalletConnect implements Wallet { }) } - onDisplayUri = async (uri: string) => { + handleDisplayUri = async (uri: string) => { await this.modal?.openModal({ uri, chains: this.getChains() }) } - onSessionUpdate = ({ session }: { session: SessionTypes.Struct }) => { + handleSessionUpdate = ({ session }: { session: SessionTypes.Struct }) => { this._session = session } + handleSessionDelete = () => { + this.disconnect() + this.onSessionDelete() + } + enable = async (dappName: string) => { if (!dappName) { throw new Error("MissingParamsError: Dapp name is required.") @@ -219,7 +237,7 @@ export class WalletConnect implements Wallet { try { const session = await provider.connect({ - namespaces: this.namespace, + optionalNamespaces: this.namespace, }) if (!session) { diff --git a/src/sections/web3-connect/wallets/index.ts b/src/sections/web3-connect/wallets/index.ts index 3b6d7de47..9c584144d 100644 --- a/src/sections/web3-connect/wallets/index.ts +++ b/src/sections/web3-connect/wallets/index.ts @@ -66,6 +66,10 @@ const walletConnect: Wallet = new WalletConnect({ state.toggle() } }, + onSesssionDelete: () => { + const state = useWeb3ConnectStore.getState() + state.disconnect() + }, }) const externalWallet: Wallet = new ExternalWallet() diff --git a/src/utils/metamask.ts b/src/utils/metamask.ts index bfa0849c7..d7d112ad3 100644 --- a/src/utils/metamask.ts +++ b/src/utils/metamask.ts @@ -3,6 +3,7 @@ import { Maybe } from "utils/helpers" import type { ExternalProvider } from "@ethersproject/providers" import type EventEmitter from "events" import { evmChains } from "@galacticcouncil/xcm-sdk" +import UniversalProvider from "@walletconnect/universal-provider/dist/types/UniversalProvider" const METAMASK_LIKE_CHECKS = ["isTalisman"] as const type MetaMaskLikeChecksValues = (typeof METAMASK_LIKE_CHECKS)[number] @@ -63,6 +64,12 @@ export function isTalisman( return isMetaMaskLike(provider) && !!provider?.isTalisman } +export function isEthereumProvider( + provider: Maybe, +): provider is Required { + return typeof provider?.request === "function" +} + type RequestNetworkSwitchOptions = { onSwitch?: () => void chain?: keyof typeof evmChains @@ -71,7 +78,7 @@ export async function requestNetworkSwitch( provider: Maybe, options: RequestNetworkSwitchOptions = {}, ) { - if (!isMetaMask(provider)) return + if (!isEthereumProvider(provider)) return const params = getAddEvmChainParams(options.chain ?? "hydradx") @@ -83,8 +90,18 @@ export async function requestNetworkSwitch( }) .then(options?.onSwitch) } catch (error: any) { + let message: Record = {} + try { + message = + typeof error?.message === "string" ? JSON.parse(error.message) : {} + } catch (err) {} + + const errorCode = + message?.data?.originalError?.code || + error.data?.originalError?.code || + error?.code + // missing or unsupported network error - const errorCode = error.data?.originalError?.code || error?.code if (errorCode === 4902) { try { await provider @@ -94,6 +111,8 @@ export async function requestNetworkSwitch( }) .then(options?.onSwitch) } catch (err) {} + } else { + throw new Error(error) } } } diff --git a/yarn.lock b/yarn.lock index 31c5040c6..2f11e7909 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3272,31 +3272,6 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@json-rpc-tools/provider@^1.5.5": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@json-rpc-tools/provider/-/provider-1.7.6.tgz#8a17c34c493fa892632e278fd9331104e8491ec6" - integrity sha512-z7D3xvJ33UfCGv77n40lbzOYjZKVM3k2+5cV7xS8G6SCvKTzMkhkUYuD/qzQUNT4cG/lv0e9mRToweEEVLVVmA== - dependencies: - "@json-rpc-tools/utils" "^1.7.6" - axios "^0.21.0" - safe-json-utils "^1.1.1" - ws "^7.4.0" - -"@json-rpc-tools/types@^1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@json-rpc-tools/types/-/types-1.7.6.tgz#5abd5fde01364a130c46093b501715bcce5bdc0e" - integrity sha512-nDSqmyRNEqEK9TZHtM15uNnDljczhCUdBmRhpNZ95bIPKEDQ+nTDmGMFd2lLin3upc5h2VVVd9tkTDdbXUhDIQ== - dependencies: - keyvaluestorage-interface "^1.0.0" - -"@json-rpc-tools/utils@^1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@json-rpc-tools/utils/-/utils-1.7.6.tgz#67f04987dbaa2e7adb6adff1575367b75a9a9ba1" - integrity sha512-HjA8x/U/Q78HRRe19yh8HVKoZ+Iaoo3YZjakJYxR+rw52NHo6jM+VE9b8+7ygkCFXl/EHID5wh/MkXaE/jGyYw== - dependencies: - "@json-rpc-tools/types" "^1.7.6" - "@pedrouid/environment" "^1.0.1" - "@juggle/resize-observer@^3.3.1": version "3.4.0" resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60" @@ -3568,6 +3543,98 @@ dependencies: "@open-web3/orml-type-definitions" "^2.0.1" +"@parcel/watcher-android-arm64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz#c2c19a3c442313ff007d2d7a9c2c1dd3e1c9ca84" + integrity sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg== + +"@parcel/watcher-darwin-arm64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz#c817c7a3b4f3a79c1535bfe54a1c2818d9ffdc34" + integrity sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA== + +"@parcel/watcher-darwin-x64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz#1a3f69d9323eae4f1c61a5f480a59c478d2cb020" + integrity sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg== + +"@parcel/watcher-freebsd-x64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz#0d67fef1609f90ba6a8a662bc76a55fc93706fc8" + integrity sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w== + +"@parcel/watcher-linux-arm-glibc@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz#ce5b340da5829b8e546bd00f752ae5292e1c702d" + integrity sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA== + +"@parcel/watcher-linux-arm64-glibc@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz#6d7c00dde6d40608f9554e73998db11b2b1ff7c7" + integrity sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA== + +"@parcel/watcher-linux-arm64-musl@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz#bd39bc71015f08a4a31a47cd89c236b9d6a7f635" + integrity sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA== + +"@parcel/watcher-linux-x64-glibc@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz#0ce29966b082fb6cdd3de44f2f74057eef2c9e39" + integrity sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg== + +"@parcel/watcher-linux-x64-musl@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz#d2ebbf60e407170bb647cd6e447f4f2bab19ad16" + integrity sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ== + +"@parcel/watcher-wasm@^2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-wasm/-/watcher-wasm-2.4.1.tgz#c4353e4fdb96ee14389856f7f6f6d21b7dcef9e1" + integrity sha512-/ZR0RxqxU/xxDGzbzosMjh4W6NdYFMqq2nvo2b8SLi7rsl/4jkL8S5stIikorNkdR50oVDvqb/3JT05WM+CRRA== + dependencies: + is-glob "^4.0.3" + micromatch "^4.0.5" + napi-wasm "^1.1.0" + +"@parcel/watcher-win32-arm64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz#eb4deef37e80f0b5e2f215dd6d7a6d40a85f8adc" + integrity sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg== + +"@parcel/watcher-win32-ia32@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz#94fbd4b497be39fd5c8c71ba05436927842c9df7" + integrity sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw== + +"@parcel/watcher-win32-x64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz#4bf920912f67cae5f2d264f58df81abfea68dadf" + integrity sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A== + +"@parcel/watcher@^2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.4.1.tgz#a50275151a1bb110879c6123589dba90c19f1bf8" + integrity sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA== + dependencies: + detect-libc "^1.0.3" + is-glob "^4.0.3" + micromatch "^4.0.5" + node-addon-api "^7.0.0" + optionalDependencies: + "@parcel/watcher-android-arm64" "2.4.1" + "@parcel/watcher-darwin-arm64" "2.4.1" + "@parcel/watcher-darwin-x64" "2.4.1" + "@parcel/watcher-freebsd-x64" "2.4.1" + "@parcel/watcher-linux-arm-glibc" "2.4.1" + "@parcel/watcher-linux-arm64-glibc" "2.4.1" + "@parcel/watcher-linux-arm64-musl" "2.4.1" + "@parcel/watcher-linux-x64-glibc" "2.4.1" + "@parcel/watcher-linux-x64-musl" "2.4.1" + "@parcel/watcher-win32-arm64" "2.4.1" + "@parcel/watcher-win32-ia32" "2.4.1" + "@parcel/watcher-win32-x64" "2.4.1" + "@peaqnetwork/type-definitions@0.0.4": version "0.0.4" resolved "https://registry.yarnpkg.com/@peaqnetwork/type-definitions/-/type-definitions-0.0.4.tgz#a893ff95bf824d13c902d3b5912b2954fc12e1e6" @@ -3575,11 +3642,6 @@ dependencies: "@open-web3/orml-type-definitions" "^0.9.4-38" -"@pedrouid/environment@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@pedrouid/environment/-/environment-1.0.1.tgz#858f0f8a057340e0b250398b75ead77d6f4342ec" - integrity sha512-HaW78NszGzRZd9SeoI3JD11JqY+lubnaOx7Pewj5pfjqWXOEATpeKIFb9Z4t2WBUK2iryiXX3lzWwmYWgUL0Ug== - "@phala/typedefs@0.2.33": version "0.2.33" resolved "https://registry.yarnpkg.com/@phala/typedefs/-/typedefs-0.2.33.tgz#6f18d73b5104db6a594d08be571954385b3e509b" @@ -6873,25 +6935,26 @@ loupe "^2.3.6" pretty-format "^29.5.0" -"@walletconnect/core@2.8.0": - version "2.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.8.0.tgz#f694e1562413c4eb700f6b3a83fa7964342100c0" - integrity sha512-pl7x4sq1nuU0ixA9wF2ecjDecUzIauKr7ZwC29rs9qTcmDpxgJbbOdZwaSl+dJlf1bHC87adVLf5KAkwwo9PzQ== +"@walletconnect/core@2.12.2": + version "2.12.2" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.12.2.tgz#12bd568b90daed876e58ebcc098c12843a3321e6" + integrity sha512-7Adv/b3pp9F42BkvReaaM4KS8NEvlkS7AMtwO3uF/o6aRMKtcfTJq9/jgWdKJh4RP8pPRTRFjCw6XQ/RZtT4aQ== dependencies: "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-provider" "1.0.13" "@walletconnect/jsonrpc-types" "1.0.3" "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/jsonrpc-ws-connection" "^1.0.11" - "@walletconnect/keyvaluestorage" "^1.0.2" - "@walletconnect/logger" "^2.0.1" + "@walletconnect/jsonrpc-ws-connection" "1.0.14" + "@walletconnect/keyvaluestorage" "^1.1.1" + "@walletconnect/logger" "^2.1.2" "@walletconnect/relay-api" "^1.0.9" "@walletconnect/relay-auth" "^1.0.4" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.8.0" - "@walletconnect/utils" "2.8.0" + "@walletconnect/types" "2.12.2" + "@walletconnect/utils" "2.12.2" events "^3.3.0" + isomorphic-unfetch "3.1.0" lodash.isequal "4.5.0" uint8arrays "^3.1.0" @@ -6955,24 +7018,24 @@ "@walletconnect/jsonrpc-types" "^1.0.3" tslib "1.14.1" -"@walletconnect/jsonrpc-ws-connection@^1.0.11": - version "1.0.13" - resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.13.tgz#23b0cdd899801bfbb44a6556936ec2b93ef2adf4" - integrity sha512-mfOM7uFH4lGtQxG+XklYuFBj6dwVvseTt5/ahOkkmpcAEgz2umuzu7fTR+h5EmjQBdrmYyEBOWADbeaFNxdySg== +"@walletconnect/jsonrpc-ws-connection@1.0.14": + version "1.0.14" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.14.tgz#eec700e74766c7887de2bd76c91a0206628732aa" + integrity sha512-Jsl6fC55AYcbkNVkwNM6Jo+ufsuCQRqViOQ8ZBPH9pRREHH9welbBiszuTLqEJiQcO/6XfFDl6bzCJIkrEi8XA== dependencies: "@walletconnect/jsonrpc-utils" "^1.0.6" "@walletconnect/safe-json" "^1.0.2" events "^3.3.0" - tslib "1.14.1" ws "^7.5.1" -"@walletconnect/keyvaluestorage@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.0.2.tgz#92f5ca0f54c1a88a093778842ce0c874d86369c8" - integrity sha512-U/nNG+VLWoPFdwwKx0oliT4ziKQCEoQ27L5Hhw8YOFGA2Po9A9pULUYNWhDgHkrb0gYDNt//X7wABcEWWBd3FQ== +"@walletconnect/keyvaluestorage@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz#dd2caddabfbaf80f6b8993a0704d8b83115a1842" + integrity sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA== dependencies: - safe-json-utils "^1.1.1" - tslib "1.14.1" + "@walletconnect/safe-json" "^1.0.1" + idb-keyval "^6.2.1" + unstorage "^1.9.0" "@walletconnect/logger@^2.0.1": version "2.0.1" @@ -6982,6 +7045,14 @@ pino "7.11.0" tslib "1.14.1" +"@walletconnect/logger@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@walletconnect/logger/-/logger-2.1.2.tgz#813c9af61b96323a99f16c10089bfeb525e2a272" + integrity sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw== + dependencies: + "@walletconnect/safe-json" "^1.0.2" + pino "7.11.0" + "@walletconnect/modal-core@2.6.2": version "2.6.2" resolved "https://registry.yarnpkg.com/@walletconnect/modal-core/-/modal-core-2.6.2.tgz#d73e45d96668764e0c8668ea07a45bb8b81119e9" @@ -7034,19 +7105,19 @@ dependencies: tslib "1.14.1" -"@walletconnect/sign-client@2.8.0": - version "2.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.8.0.tgz#735dc8bf120242584fb2ff22c6a3d672c1fae1a1" - integrity sha512-+l9qwvVeUGk0fBQsgx6yb6hdGYt8uQ3a9jR9GgsJvm8FjFh1oUzTKqFnG7XdhCBnzFnbSoLr41Xe8PbN8qoUSw== +"@walletconnect/sign-client@2.12.2": + version "2.12.2" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.12.2.tgz#10cddcba3740f726149c33ef1a9040a808d65e08" + integrity sha512-cM0ualXj6nVvLqS4BDNRk+ZWR+lubcsz/IHreH+3wYrQ2sV+C0fN6ctrd7MMGZss0C0qacWCx0pm62ZBuoKvqA== dependencies: - "@walletconnect/core" "2.8.0" + "@walletconnect/core" "2.12.2" "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/logger" "^2.0.1" + "@walletconnect/logger" "^2.1.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.8.0" - "@walletconnect/utils" "2.8.0" + "@walletconnect/types" "2.12.2" + "@walletconnect/utils" "2.12.2" events "^3.3.0" "@walletconnect/time@^1.0.2": @@ -7056,38 +7127,37 @@ dependencies: tslib "1.14.1" -"@walletconnect/types@2.8.0", "@walletconnect/types@^2.8.0": - version "2.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.8.0.tgz#f8a5f09ee2b31abed231966e7e1eebd22be058a2" - integrity sha512-FMeGK3lGXFDwcs5duoN74xL1aLrkgYqnavWE0DnFPt2i1QmSUITU9c8f88EDh8uPXANd2WIYOItm0DVCNxLGGA== +"@walletconnect/types@2.12.2", "@walletconnect/types@^2.12.2": + version "2.12.2" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.12.2.tgz#8b64a2015a0a96972d28acb2ff317a9a994abfdb" + integrity sha512-9CmwTlPbrFTzayTL9q7xM7s3KTJkS6kYFtH2m1/fHFgALs6pIUjf1qAx1TF2E4tv7SEzLAIzU4NqgYUt2vWXTg== dependencies: "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-types" "1.0.3" - "@walletconnect/keyvaluestorage" "^1.0.2" + "@walletconnect/keyvaluestorage" "^1.1.1" "@walletconnect/logger" "^2.0.1" events "^3.3.0" -"@walletconnect/universal-provider@2.8.0": - version "2.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.8.0.tgz#134f6873742f672c2424969335f9cc75d1532d17" - integrity sha512-BMsGiINI3rT7DRyDJM7miuWG6vDVE0PV6zMcCXIMDYYPay7zFvJxv2VHEx9an4MutrvQR76NTRyG//i1K84VOQ== +"@walletconnect/universal-provider@2.12.2": + version "2.12.2" + resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.12.2.tgz#0c855bbb5584fd11bdf2318344fe6f42fa3e91cb" + integrity sha512-0k5ZgSkABopQLVhkiwl2gRGG7dAP4SWiI915pIlyN5sRvWV+qX1ALhWAmRcdv0TXWlKHDcDgPJw/q2sCSAHuMQ== dependencies: "@walletconnect/jsonrpc-http-connection" "^1.0.7" "@walletconnect/jsonrpc-provider" "1.0.13" "@walletconnect/jsonrpc-types" "^1.0.2" "@walletconnect/jsonrpc-utils" "^1.0.7" - "@walletconnect/logger" "^2.0.1" - "@walletconnect/sign-client" "2.8.0" - "@walletconnect/types" "2.8.0" - "@walletconnect/utils" "2.8.0" - eip1193-provider "1.0.1" + "@walletconnect/logger" "^2.1.2" + "@walletconnect/sign-client" "2.12.2" + "@walletconnect/types" "2.12.2" + "@walletconnect/utils" "2.12.2" events "^3.3.0" -"@walletconnect/utils@2.8.0": - version "2.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.8.0.tgz#c219e78fd2c35062cf3e37f84961afde8da9b9a1" - integrity sha512-Q8OwMtUevIn1+64LXyTMLlhH58k3UOAjU5b3smYZ7CEEmwEGpOTfTDAWrB3v+ZDIhjyqP94+8fuvKIbcVLKLWA== +"@walletconnect/utils@2.12.2": + version "2.12.2" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.12.2.tgz#a2c349d4effef7c1c5e72e74a5483d8dfbb10918" + integrity sha512-zf50HeS3SfoLv1N9GPl2IXTZ9TsXfet4usVAsZmX9P6/Xzq7d/7QakjVQCHH/Wk1O9XkcsfeoZoUhRxoMJ5uJw== dependencies: "@stablelib/chacha20poly1305" "1.0.1" "@stablelib/hkdf" "1.0.1" @@ -7097,7 +7167,7 @@ "@walletconnect/relay-api" "^1.0.9" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.8.0" + "@walletconnect/types" "2.12.2" "@walletconnect/window-getters" "^1.0.1" "@walletconnect/window-metadata" "^1.0.1" detect-browser "5.3.0" @@ -7195,6 +7265,11 @@ acorn@^7.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.11.3: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + acorn@^8.4.1, acorn@^8.8.2: version "8.8.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" @@ -7282,7 +7357,7 @@ any-base@^1.1.0: resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== -anymatch@^3.0.3, anymatch@~3.1.2: +anymatch@^3.0.3, anymatch@^3.1.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -7467,13 +7542,6 @@ axe-core@^4.6.2: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== -axios@^0.21.0: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - axobject-query@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.1.1.tgz#3b6e5c6d4e43ca7ba51c5babf99d22a9c68485e1" @@ -7922,6 +7990,21 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chokidar@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -7942,6 +8025,13 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== +citty@^0.1.5, citty@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/citty/-/citty-0.1.6.tgz#0f7904da1ed4625e1a9ea7e0fa780981aab7c5e4" + integrity sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ== + dependencies: + consola "^3.2.3" + classnames@^2.2.5: version "2.3.2" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" @@ -7973,6 +8063,15 @@ cli-table3@^0.6.1: optionalDependencies: "@colors/colors" "1.5.0" +clipboardy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-4.0.0.tgz#e73ced93a76d19dd379ebf1f297565426dffdca1" + integrity sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w== + dependencies: + execa "^8.0.1" + is-wsl "^3.1.0" + is64bit "^2.0.0" + cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -8122,6 +8221,11 @@ confusing-browser-globals@^1.0.11: resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== +consola@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/consola/-/consola-3.2.3.tgz#0741857aa88cfa0d6fd53f1cff0375136e98502f" + integrity sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ== + content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -8144,6 +8248,11 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +cookie-es@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.1.0.tgz#68f8d9f48aeb5a534f3896f80e792760d3d20def" + integrity sha512-L2rLOcK0wzWSfSDA33YR+PUHDG10a8px7rUHKWbGLP4YfbsMed2KFUw5fczvDPbT98DDe3LEzviswl810apTEw== + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" @@ -8240,6 +8349,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crossws@^0.2.0, crossws@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.2.4.tgz#82a8b518bff1018ab1d21ced9e35ffbe1681ad03" + integrity sha512-DAxroI2uSOgUKLz00NX6A8U/8EE3SZHmIND+10jkVSaypvyt57J5JEOxAQOL6lQxyzi/wZbTIwssU1uy69h5Vg== + crypt@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" @@ -8528,6 +8642,11 @@ defu@^6.1.2: resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.2.tgz#1217cba167410a1765ba93893c6dbac9ed9d9e5c" integrity sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ== +defu@^6.1.3, defu@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" + integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== + del@^6.0.0: version "6.1.1" resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" @@ -8557,6 +8676,11 @@ dequal@^2.0.2: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== +destr@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.3.tgz#7f9e97cb3d16dbdca7be52aca1644ce402cfe449" + integrity sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ== + destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -8572,6 +8696,11 @@ detect-indent@^6.1.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + detect-node-es@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" @@ -8688,13 +8817,6 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -eip1193-provider@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/eip1193-provider/-/eip1193-provider-1.0.1.tgz#420d29cf4f6c443e3f32e718fb16fafb250637c3" - integrity sha512-kSuqwQ26d7CzuS/t3yRXo2Su2cVH0QfvyKbr2H7Be7O5YDyIq4hQGCNTo5wRdP07bt+E2R/8nPCzey4ojBHf7g== - dependencies: - "@json-rpc-tools/provider" "^1.5.5" - ejs@^3.1.8: version "3.1.9" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" @@ -9356,6 +9478,21 @@ execa@^7.1.1: signal-exit "^3.0.7" strip-final-newline "^3.0.0" +execa@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + expect@^29.0.0: version "29.5.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7" @@ -9686,11 +9823,6 @@ flux@^4.0.1: fbemitter "^3.0.0" fbjs "^3.0.1" -follow-redirects@^1.14.0: - version "1.15.3" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" - integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== - for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -9849,6 +9981,11 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-port-please@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/get-port-please/-/get-port-please-3.1.2.tgz#502795e56217128e4183025c89a48c71652f4e49" + integrity sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ== + get-port@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" @@ -9859,6 +9996,11 @@ get-stream@^6.0.0, get-stream@^6.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -10019,6 +10161,22 @@ gunzip-maybe@^1.4.2: pumpify "^1.3.3" through2 "^2.0.3" +h3@^1.10.2, h3@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.11.1.tgz#e9414ae6f2a076a345ea07256b320edb29bab9f7" + integrity sha512-AbaH6IDnZN6nmbnJOH72y3c5Wwh9P97soSVdGSBbcDACRdkC0FEWf25pzx4f/NuOCK6quHmW18yF2Wx+G4Zi1A== + dependencies: + cookie-es "^1.0.0" + crossws "^0.2.2" + defu "^6.1.4" + destr "^2.0.3" + iron-webcrypto "^1.0.0" + ohash "^1.1.3" + radix3 "^1.1.0" + ufo "^1.4.0" + uncrypto "^0.1.3" + unenv "^1.9.0" + handlebars@^4.7.7: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" @@ -10146,6 +10304,11 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" +http-shutdown@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/http-shutdown/-/http-shutdown-1.2.2.tgz#41bc78fc767637c4c95179bc492f312c0ae64c5f" + integrity sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw== + https-proxy-agent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" @@ -10172,6 +10335,11 @@ human-signals@^4.3.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + humanize-duration-ts@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/humanize-duration-ts/-/humanize-duration-ts-2.1.1.tgz#5382b2789f851005a67229eaf031931d71f37ee9" @@ -10208,6 +10376,11 @@ icss-utils@^5.0.0, icss-utils@^5.1.0: resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== +idb-keyval@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.1.tgz#94516d625346d16f56f3b33855da11bfded2db33" + integrity sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg== + ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -10293,6 +10466,11 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +iron-webcrypto@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.1.0.tgz#f902f0cdbd77554b2195ecbb65558c311b01edfd" + integrity sha512-5vgYsCakNlaQub1orZK5QmNYhwYtcllTkZBp5sfIaCqY93Cf6l+v2rtE+E4TMbcfjxDMCdrO8wmp7+ZvhDECLA== + is-absolute-url@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" @@ -10580,6 +10758,20 @@ is-wsl@^2.1.1, is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" +is-wsl@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-3.1.0.tgz#e1c657e39c10090afcbedec61720f6b924c3cbd2" + integrity sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw== + dependencies: + is-inside-container "^1.0.0" + +is64bit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is64bit/-/is64bit-2.0.0.tgz#198c627cbcb198bbec402251f88e5e1a51236c07" + integrity sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw== + dependencies: + system-architecture "^0.1.0" + isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" @@ -10600,6 +10792,14 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== +isomorphic-unfetch@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" + integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== + dependencies: + node-fetch "^2.6.1" + unfetch "^4.2.0" + isows@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.3.tgz#93c1cf0575daf56e7120bab5c8c448b0809d0d74" @@ -10801,6 +11001,11 @@ jiti@^1.18.2: resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.1.tgz#fa99e4b76a23053e0e7cde098efe1704a14c16f1" integrity sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg== +jiti@^1.21.0: + version "1.21.0" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" + integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== + js-cookie@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" @@ -10998,6 +11203,30 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +listhen@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.7.2.tgz#66b81740692269d5d8cafdc475020f2fc51afbae" + integrity sha512-7/HamOm5YD9Wb7CFgAZkKgVPA96WwhcTQoqtm2VTZGVbVVn3IWKRBTgrU7cchA3Q8k9iCsG8Osoi9GX4JsGM9g== + dependencies: + "@parcel/watcher" "^2.4.1" + "@parcel/watcher-wasm" "^2.4.1" + citty "^0.1.6" + clipboardy "^4.0.0" + consola "^3.2.3" + crossws "^0.2.0" + defu "^6.1.4" + get-port-please "^3.1.2" + h3 "^1.10.2" + http-shutdown "^1.2.2" + jiti "^1.21.0" + mlly "^1.6.1" + node-forge "^1.3.1" + pathe "^1.1.2" + std-env "^3.7.0" + ufo "^1.4.0" + untun "^0.1.3" + uqr "^0.1.2" + lit-element@^3.3.0: version "3.3.3" resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.3.3.tgz#10bc19702b96ef5416cf7a70177255bfb17b3209" @@ -11138,6 +11367,11 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" +lru-cache@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" + integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -11293,7 +11527,7 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^4.0.2, micromatch@^4.0.4: +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -11323,6 +11557,11 @@ mime@^2.0.3: resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== +mime@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -11426,6 +11665,16 @@ mlly@^1.2.0, mlly@^1.4.0: pkg-types "^1.0.3" ufo "^1.1.2" +mlly@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.6.1.tgz#0983067dc3366d6314fc5e12712884e6978d028f" + integrity sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA== + dependencies: + acorn "^8.11.3" + pathe "^1.1.2" + pkg-types "^1.0.3" + ufo "^1.3.2" + mock-socket@^9.2.1: version "9.2.1" resolved "https://registry.yarnpkg.com/mock-socket/-/mock-socket-9.2.1.tgz#cc9c0810aa4d0afe02d721dcb2b7e657c00e2282" @@ -11505,6 +11754,11 @@ nanoid@^3.3.7: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +napi-wasm@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/napi-wasm/-/napi-wasm-1.1.0.tgz#bbe617823765ae9c1bc12ff5942370eae7b2ba4e" + integrity sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg== + natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" @@ -11548,6 +11802,11 @@ nock@^13.3.1: lodash "^4.17.21" propagate "^2.0.0" +node-addon-api@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.0.tgz#71f609369379c08e251c558527a107107b5e0fdb" + integrity sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g== + node-dir@^0.1.10, node-dir@^0.1.17: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" @@ -11565,6 +11824,11 @@ node-fetch-native@^1.0.2: resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.2.0.tgz#13ec6df98f33168958dbfb6945f10aedf42e7ea8" integrity sha512-5IAMBTl9p6PaAjYCnMv5FmqIF6GcZnawAVnzaCG0rX2aYZJ4CxEkZNtVPuTRug7fL7wyM5BQYTlAzcyMPi6oTQ== +node-fetch-native@^1.6.1, node-fetch-native@^1.6.2, node-fetch-native@^1.6.3: + version "1.6.4" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e" + integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ== + node-fetch@2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -11579,7 +11843,7 @@ node-fetch@^2.0.0: dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.12: +node-fetch@^2.6.1, node-fetch@^2.6.12: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -11604,6 +11868,11 @@ node-fetch@^3.3.2: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" +node-forge@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -11731,6 +12000,20 @@ object.values@^1.1.6: define-properties "^1.1.4" es-abstract "^1.20.4" +ofetch@^1.3.3: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.4.tgz#7ea65ced3c592ec2b9906975ae3fe1d26a56f635" + integrity sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw== + dependencies: + destr "^2.0.3" + node-fetch-native "^1.6.3" + ufo "^1.5.3" + +ohash@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ohash/-/ohash-1.1.3.tgz#f12c3c50bfe7271ce3fd1097d42568122ccdcf07" + integrity sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw== + on-exit-leak-free@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209" @@ -12017,6 +12300,11 @@ pathe@^1.1.1: resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.1.tgz#1dd31d382b974ba69809adc9a7a347e65d84829a" integrity sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q== +pathe@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" + integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== + pathval@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" @@ -12460,6 +12748,11 @@ quick-format-unescaped@^4.0.3: resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== +radix3@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.2.tgz#fd27d2af3896c6bf4bcdfab6427c69c2afc69ec0" + integrity sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA== + ramda@0.29.0: version "0.29.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.29.0.tgz#fbbb67a740a754c8a4cbb41e2a6e0eb8507f55fb" @@ -13053,11 +13346,6 @@ safe-buffer@5.2.1, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-json-utils@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/safe-json-utils/-/safe-json-utils-1.1.1.tgz#0e883874467d95ab914c3f511096b89bfb3e63b1" - integrity sha512-SAJWGKDs50tAbiDXLf89PDwt9XYkWyANFWVzn4dTXl5QyI8t2o/bW5/OJl3lvc2WVU4MEpTo9Yz5NVFNsp+OJQ== - safe-regex-test@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" @@ -13268,6 +13556,11 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.2.tgz#ff55bb1d9ff2114c13b400688fa544ac63c36967" integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q== +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" @@ -13450,6 +13743,11 @@ std-env@^3.3.3: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.3.3.tgz#a54f06eb245fdcfef53d56f3c0251f1d5c3d01fe" integrity sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg== +std-env@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" + integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== + stop-iteration-iterator@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" @@ -13686,6 +13984,11 @@ synckit@^0.8.5: "@pkgr/utils" "^2.3.1" tslib "^2.5.0" +system-architecture@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/system-architecture/-/system-architecture-0.1.0.tgz#71012b3ac141427d97c67c56bc7921af6bff122d" + integrity sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA== + tar-fs@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" @@ -14024,6 +14327,11 @@ ufo@^1.1.2: resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.1.2.tgz#d0d9e0fa09dece0c31ffd57bd363f030a35cfe76" integrity sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ== +ufo@^1.3.2, ufo@^1.4.0, ufo@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344" + integrity sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw== + uglify-js@^3.1.4: version "3.17.4" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" @@ -14046,6 +14354,27 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +uncrypto@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/uncrypto/-/uncrypto-0.1.3.tgz#e1288d609226f2d02d8d69ee861fa20d8348ef2b" + integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q== + +unenv@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.9.0.tgz#469502ae85be1bd3a6aa60f810972b1a904ca312" + integrity sha512-QKnFNznRxmbOF1hDgzpqrlIf6NC5sbZ2OJ+5Wl3OX8uM+LUJXbj4TXvLJCtwbPTmbMHCLIz6JLKNinNsMShK9g== + dependencies: + consola "^3.2.3" + defu "^6.1.3" + mime "^3.0.0" + node-fetch-native "^1.6.1" + pathe "^1.1.1" + +unfetch@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" + integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" @@ -14118,11 +14447,36 @@ unplugin@^1.3.1: webpack-sources "^3.2.3" webpack-virtual-modules "^0.5.0" +unstorage@^1.9.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.10.2.tgz#fb7590ada8b30e83be9318f85100158b02a76dae" + integrity sha512-cULBcwDqrS8UhlIysUJs2Dk0Mmt8h7B0E6mtR+relW9nZvsf/u4SkAYyNliPiPW7XtFNb5u3IUMkxGxFTTRTgQ== + dependencies: + anymatch "^3.1.3" + chokidar "^3.6.0" + destr "^2.0.3" + h3 "^1.11.1" + listhen "^1.7.2" + lru-cache "^10.2.0" + mri "^1.2.0" + node-fetch-native "^1.6.2" + ofetch "^1.3.3" + ufo "^1.4.0" + untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== +untun@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/untun/-/untun-0.1.3.tgz#5d10dee37a3a5737ff03d158be877dae0a0e58a6" + integrity sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ== + dependencies: + citty "^0.1.5" + consola "^3.2.3" + pathe "^1.1.1" + update-browserslist-db@^1.0.10, update-browserslist-db@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" @@ -14131,6 +14485,11 @@ update-browserslist-db@^1.0.10, update-browserslist-db@^1.0.11: escalade "^3.1.1" picocolors "^1.0.0" +uqr@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/uqr/-/uqr-0.1.2.tgz#5c6cd5dcff9581f9bb35b982cb89e2c483a41d7d" + integrity sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA== + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -14553,7 +14912,7 @@ ws@^6.1.0: dependencies: async-limiter "~1.0.0" -ws@^7.4.0, ws@^7.5.1: +ws@^7.5.1: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== From 3f99583e6ec747ef3d14f02b0d1ca4f76cd0de96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Tue, 16 Apr 2024 17:46:19 +0200 Subject: [PATCH 030/103] Show correct icon for bonds in OTC fill order --- .../trade/sections/otc/modals/cmp/AssetSelect.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sections/trade/sections/otc/modals/cmp/AssetSelect.tsx b/src/sections/trade/sections/otc/modals/cmp/AssetSelect.tsx index 60b31a88b..81f610353 100644 --- a/src/sections/trade/sections/otc/modals/cmp/AssetSelect.tsx +++ b/src/sections/trade/sections/otc/modals/cmp/AssetSelect.tsx @@ -107,6 +107,8 @@ export function OrderAssetPay(props: { }) { const { assets } = useRpcProvider() const asset = assets.getAsset(props.asset.toString()) + const isBond = assets.isBond(asset) + const assetDetails = isBond ? assets.getAsset(asset.assetId) : asset const assetBalance = props.balance const assetDecimals = asset.decimals @@ -140,8 +142,8 @@ export function OrderAssetPay(props: { selectable={false} readonly={props.readonly || false} > - - + + @@ -181,6 +183,9 @@ export function OrderAssetGet(props: { }) { const { assets } = useRpcProvider() const asset = assets.getAsset(props.asset.toString()) + const isBond = assets.isBond(asset) + const assetDetails = isBond ? assets.getAsset(asset.assetId) : asset + return ( { @@ -206,8 +211,8 @@ export function OrderAssetGet(props: { selectable={false} readonly={props.readonly || false} > - - + + {props.onChange && (
From 5f6179282cb2d2fc4a9c843af9134816dbcb0dca Mon Sep 17 00:00:00 2001 From: vkulinich Date: Tue, 16 Apr 2024 21:47:28 +0200 Subject: [PATCH 031/103] fix farms claiming --- src/api/deposits.ts | 1 + src/api/farms.ts | 70 ++++++++++++++++-------- src/utils/farms/claiming.ts | 18 ++++-- src/utils/farms/claiming/mutableFarms.ts | 70 ++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 29 deletions(-) diff --git a/src/api/deposits.ts b/src/api/deposits.ts index f4a651c7d..aa22937e8 100644 --- a/src/api/deposits.ts +++ b/src/api/deposits.ts @@ -10,6 +10,7 @@ import { useAccount } from "sections/web3-connect/Web3Connect.utils" export type TDeposit = { id: string data: PalletLiquidityMiningDepositData + isXyk: boolean } export const useOmnipoolDeposits = (ids: string[]) => { diff --git a/src/api/farms.ts b/src/api/farms.ts index a003132d5..1071cb8d5 100644 --- a/src/api/farms.ts +++ b/src/api/farms.ts @@ -89,13 +89,16 @@ export function useYieldFarms(ids: FarmIds[]) { queryKey: isXYK ? QUERY_KEYS.yieldFarmXYK(poolId) : QUERY_KEYS.yieldFarm(poolId), - queryFn: getYieldFarm( - api, - isXYK ? meta.poolAddress : poolId, - globalFarmId, - yieldFarmId, - isXYK, - ), + queryFn: async () => { + const farm = await getYieldFarm( + api, + isXYK ? meta.poolAddress : poolId, + globalFarmId, + yieldFarmId, + isXYK, + )() + return { farm, poolId } + }, enabled: poolId != null, } }), @@ -138,7 +141,10 @@ export function useGlobalFarms(ids: FarmIds[]) { queryKey: isXYK ? QUERY_KEYS.globalFarmXYK(poolId) : QUERY_KEYS.globalFarm(poolId), - queryFn: getGlobalFarm(api, globalFarmId, isXYK), + queryFn: async () => { + const farm = await getGlobalFarm(api, globalFarmId, isXYK)() + return { farm, poolId } + }, enabled: poolId != null, } }), @@ -176,14 +182,23 @@ export const useFarms = (poolIds: Array) => { const data = useMemo(() => { return farmIds .map((farmId) => { - const globalFarm = globalFarms.find( - (globalFarm) => - globalFarm.data?.id.toString() === farmId.globalFarmId, - )?.data + const globalFarm = globalFarms.find((globalFarm) => { + const data = globalFarm.data + + return ( + data?.farm.id.toString() === farmId.globalFarmId && + data.poolId === farmId.poolId + ) + })?.data?.farm + + const yieldFarm = yieldFarms.find((yieldFarm) => { + const data = yieldFarm.data - const yieldFarm = yieldFarms.find( - (yieldFarm) => yieldFarm.data?.id.toString() === farmId.yieldFarmId, - )?.data + return ( + data?.farm.id.toString() === farmId.yieldFarmId && + data.poolId === farmId.poolId + ) + })?.data?.farm if (!globalFarm || !yieldFarm) return undefined @@ -559,14 +574,23 @@ export const useInactiveFarms = (poolIds: Array) => { const data = useMemo(() => { return farmIds .map((farmId) => { - const globalFarm = globalFarms.find( - (globalFarm) => - globalFarm.data?.id.toString() === farmId.globalFarmId, - )?.data - - const yieldFarm = yieldFarms.find( - (yieldFarm) => yieldFarm.data?.id.toString() === farmId.yieldFarmId, - )?.data + const globalFarm = globalFarms.find((globalFarm) => { + const data = globalFarm.data + + return ( + data?.farm.id.toString() === farmId.globalFarmId && + data.poolId === farmId.poolId + ) + })?.data?.farm + + const yieldFarm = yieldFarms.find((yieldFarm) => { + const data = yieldFarm.data + + return ( + data?.farm.id.toString() === farmId.yieldFarmId && + data.poolId === farmId.poolId + ) + })?.data?.farm if (!globalFarm || !yieldFarm) return undefined diff --git a/src/utils/farms/claiming.ts b/src/utils/farms/claiming.ts index 26cd6196c..552a97aa7 100644 --- a/src/utils/farms/claiming.ts +++ b/src/utils/farms/claiming.ts @@ -15,7 +15,7 @@ import { useDisplayPrices } from "utils/displayAsset" import { getAccountResolver } from "./claiming/accountResolver" import { OmnipoolLiquidityMiningClaimSim } from "./claiming/claimSimulator" import { MultiCurrencyContainer } from "./claiming/multiCurrency" -import { createMutableFarmEntries } from "./claiming/mutableFarms" +import { createMutableFarmEntry } from "./claiming/mutableFarms" import { useRpcProvider } from "providers/rpcProvider" export const useClaimableAmount = (poolId?: string, depositNft?: TDeposit) => { @@ -119,15 +119,19 @@ export const useClaimableAmount = (poolId?: string, depositNft?: TDeposit) => { metas ?? [], ) - const { globalFarms, yieldFarms } = createMutableFarmEntries(allFarms ?? []) - return deposits ?.map((record) => record.data.yieldFarmEntries.map((farmEntry) => { + const poolId = record.isXyk + ? assets.getShareTokenByAddress(record.data.ammPoolId.toString()) + ?.id + : record.data.ammPoolId.toString() + const aprEntry = allFarms.find( (i) => i.globalFarm.id.eq(farmEntry.globalFarmId) && - i.yieldFarm.id.eq(farmEntry.yieldFarmId), + i.yieldFarm.id.eq(farmEntry.yieldFarmId) && + i.poolId === poolId, ) if (!aprEntry) return null @@ -142,9 +146,11 @@ export const useClaimableAmount = (poolId?: string, depositNft?: TDeposit) => { if (!oracle?.data) return null + const { globalFarm, yieldFarm } = createMutableFarmEntry(aprEntry) + const reward = simulator.claim_rewards( - globalFarms[aprEntry.globalFarm.id.toString()], - yieldFarms[aprEntry.yieldFarm.id.toString()], + globalFarm, + yieldFarm, farmEntry, bestNumber.data.relaychainBlockNumber.toBigNumber(), oracle.data.oraclePrice ?? diff --git a/src/utils/farms/claiming/mutableFarms.ts b/src/utils/farms/claiming/mutableFarms.ts index fda4e2d53..3badde62f 100644 --- a/src/utils/farms/claiming/mutableFarms.ts +++ b/src/utils/farms/claiming/mutableFarms.ts @@ -118,3 +118,73 @@ export function createMutableFarmEntries( return { yieldFarms, globalFarms } } + +export function createMutableFarmEntry({ + globalFarm, + yieldFarm, +}: { + globalFarm: PalletLiquidityMiningGlobalFarmData + yieldFarm: PalletLiquidityMiningYieldFarmData +}) { + const globalFarm_ = { + id: globalFarm.id, + incentivizedAsset: globalFarm.incentivizedAsset, + owner: globalFarm.owner, + rewardCurrency: globalFarm.rewardCurrency, + state: globalFarm.state, + // PeriodOf + updatedAt: globalFarm.updatedAt.toBigNumber(), + // Balance + totalSharesZ: globalFarm.totalSharesZ.toBigNumber(), + // FixedU128 + accumulatedRpz: globalFarm.accumulatedRpz.toBigNumber(), + // Balance + pendingRewards: globalFarm.pendingRewards.toBigNumber(), + // Balance + accumulatedPaidRewards: globalFarm.accumulatedPaidRewards.toBigNumber(), + // Perquintill + yieldPerPeriod: globalFarm.yieldPerPeriod + .toBigNumber() + .dividedBy(BN_QUINTILL), + // PeriodOf + plannedYieldingPeriods: globalFarm.plannedYieldingPeriods.toBigNumber(), + // BlockNumberFor + blocksPerPeriod: globalFarm.blocksPerPeriod.toBigNumber(), + // Balance + maxRewardPerPeriod: globalFarm.maxRewardPerPeriod.toBigNumber(), + // Balance + minDeposit: globalFarm.minDeposit.toBigNumber(), + // u32 + liveYieldFarmsCount: globalFarm.liveYieldFarmsCount.toBigNumber(), + // u32 + totalYieldFarmsCount: globalFarm.totalYieldFarmsCount.toBigNumber(), + // FixedU128 + priceAdjustment: globalFarm.priceAdjustment.toBigNumber(), + } + + const yieldFarm_ = { + id: yieldFarm.id, + // PeriodOf + updatedAt: yieldFarm.updatedAt.toBigNumber(), + // Balance + totalShares: yieldFarm.totalShares.toBigNumber(), + // Balance + totalValuedShares: yieldFarm.totalValuedShares.toBigNumber(), + // FixedU128 + accumulatedRpvs: yieldFarm.accumulatedRpvs.toBigNumber(), + // FixedU128 + accumulatedRpz: yieldFarm.accumulatedRpz.toBigNumber(), + // FarmMultiplier + multiplier: yieldFarm.multiplier.toBigNumber(), + // u64 + entriesCount: yieldFarm.entriesCount.toBigNumber(), + // Balance + leftToDistribute: yieldFarm.leftToDistribute.toBigNumber(), + // PeriodOf + totalStopped: yieldFarm.totalStopped.toBigNumber(), + loyaltyCurve: yieldFarm.loyaltyCurve, + state: yieldFarm.state, + } + + return { yieldFarm: yieldFarm_, globalFarm: globalFarm_ } +} From 77c6d40171f43a4639f7c1dccc482e58b3f85059 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Tue, 16 Apr 2024 22:05:57 +0200 Subject: [PATCH 032/103] Improve add xyl liq validation --- src/api/xyk.ts | 13 ++++-- .../AddLiquidity/AddLiquidityFormXYK.tsx | 43 +++++++++++++------ 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/api/xyk.ts b/src/api/xyk.ts index 642c9f7c7..cc82fa4ec 100644 --- a/src/api/xyk.ts +++ b/src/api/xyk.ts @@ -66,14 +66,19 @@ export const useXYKConsts = () => { } const getXYKConsts = (api: ApiPromise) => async () => { - const [feeRaw, minTradingLimit] = await Promise.all([ + const [feeRaw, minTradingLimit, minPoolLiquidity] = await Promise.all([ api.consts.xyk.getExchangeFee, api.consts.xyk.minTradingLimit, + api.consts.xyk.minPoolLiquidity, ]) - //@ts-ignore - const fee = feeRaw?.map((el) => el.toString()) as string[] - return { fee: fee, minPoolLiquidity: minTradingLimit.toString() } + const fee = feeRaw.map((el) => el.toString()) + + return { + fee: fee, + minTradingLimit: minTradingLimit.toString(), + minPoolLiquidity: minPoolLiquidity.toString(), + } } export const useXYKTotalLiquidity = (address?: string) => { diff --git a/src/sections/pools/modals/AddLiquidity/AddLiquidityFormXYK.tsx b/src/sections/pools/modals/AddLiquidity/AddLiquidityFormXYK.tsx index bb7a6e083..cacef9826 100644 --- a/src/sections/pools/modals/AddLiquidity/AddLiquidityFormXYK.tsx +++ b/src/sections/pools/modals/AddLiquidity/AddLiquidityFormXYK.tsx @@ -9,7 +9,11 @@ import { Trans, useTranslation } from "react-i18next" import { PoolAddLiquidityInformationCard } from "./AddLiquidityInfoCard" import { Separator } from "components/Separator/Separator" import { Button } from "components/Button/Button" -import { getFixedPointAmount, getFloatingPointAmount } from "utils/balance" +import { + getFixedPointAmount, + getFloatingPointAmount, + scale, +} from "utils/balance" import { useStore } from "state/store" import { useCallback, useEffect, useMemo, useState } from "react" import { useRpcProvider } from "providers/rpcProvider" @@ -94,19 +98,6 @@ export const AddLiquidityFormXYK = ({ pool, onClose }: Props) => { [assetValueA, assetValueB], ) - const minAddLiquidityValidation = useMemo(() => { - const { decimals } = formAssets[lastUpdated] - - const mainAsset = new BigNumber(assetValues[lastUpdated]) - - const minAddLiqudityValue = BigNumber( - xykConsts.data?.minPoolLiquidity ?? 0, - ).shiftedBy(-decimals) - const isMinAddLiqudity = minAddLiqudityValue.gt(mainAsset) - - return isMinAddLiqudity - }, [assetValues, formAssets, lastUpdated, xykConsts.data?.minPoolLiquidity]) - const calculatedShares = useMemo(() => { if ( pool.shareTokenIssuance?.totalShare && @@ -127,6 +118,30 @@ export const AddLiquidityFormXYK = ({ pool, onClose }: Props) => { return null }, [pool, reserves.assetA, assetValues.assetA, formAssets.assetA.decimals]) + const minAddLiquidityValidation = useMemo(() => { + const minTradingLimit = BigNumber(xykConsts.data?.minTradingLimit ?? 0) + const minPoolLiquidity = BigNumber(xykConsts.data?.minPoolLiquidity ?? 0) + + if (!assetValues.assetA || !assetValues.assetB || !calculatedShares) + return false + + const minAssetATradingLimit = scale( + assetValues.assetA, + formAssets.assetA.decimals, + ).gt(minTradingLimit) + const minAssetBTradingLimit = scale( + assetValues.assetB, + formAssets.assetB.decimals, + ).gt(minTradingLimit) + + const isMinPoolLiquidity = calculatedShares.gt(minPoolLiquidity) + + const isMinAddLiqudity = + !minAssetATradingLimit || !minAssetBTradingLimit || !isMinPoolLiquidity + + return isMinAddLiqudity + }, [assetValues, formAssets, xykConsts.data, calculatedShares]) + let calculatedRatio = pool.shareTokenIssuance?.myPoolShare && calculatedShares && From fca24a6b3c6af54cb4f96239e96f2a7a2a91716d Mon Sep 17 00:00:00 2001 From: vkulinich Date: Tue, 16 Apr 2024 22:21:04 +0200 Subject: [PATCH 033/103] fix query keys --- src/api/farms.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/farms.ts b/src/api/farms.ts index 1071cb8d5..ad5536b9a 100644 --- a/src/api/farms.ts +++ b/src/api/farms.ts @@ -87,8 +87,8 @@ export function useYieldFarms(ids: FarmIds[]) { return { queryKey: isXYK - ? QUERY_KEYS.yieldFarmXYK(poolId) - : QUERY_KEYS.yieldFarm(poolId), + ? QUERY_KEYS.yieldFarmXYK(yieldFarmId) + : QUERY_KEYS.yieldFarm(yieldFarmId), queryFn: async () => { const farm = await getYieldFarm( api, @@ -139,8 +139,8 @@ export function useGlobalFarms(ids: FarmIds[]) { return { queryKey: isXYK - ? QUERY_KEYS.globalFarmXYK(poolId) - : QUERY_KEYS.globalFarm(poolId), + ? QUERY_KEYS.globalFarmXYK(globalFarmId) + : QUERY_KEYS.globalFarm(globalFarmId), queryFn: async () => { const farm = await getGlobalFarm(api, globalFarmId, isXYK)() return { farm, poolId } From af8125a47710dbacee465fb016103c7c10a13587 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Tue, 16 Apr 2024 23:41:17 +0200 Subject: [PATCH 034/103] Fix new farm apr --- src/api/farms.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/farms.ts b/src/api/farms.ts index ad5536b9a..05412a79a 100644 --- a/src/api/farms.ts +++ b/src/api/farms.ts @@ -275,7 +275,7 @@ function getFarmApr( let apr if (totalSharesZ.isZero()) { - apr = yieldPerPeriod.times(multiplier).times(periodsPerYear) + apr = yieldPerPeriod.times(multiplier).times(periodsPerYear).shiftedBy(-18) } else { const globalRewardPerPeriod = getGlobalRewardPerPeriod( totalSharesZ, From cd7a3c144eb5bf7f0b832be24cfa9c144793f93f Mon Sep 17 00:00:00 2001 From: vkulinich Date: Wed, 17 Apr 2024 09:50:36 +0200 Subject: [PATCH 035/103] Add New External Asset button --- src/hooks/useRemount.ts | 11 ++++++++--- src/sections/trade/sections/swap/SwapPage.tsx | 12 +++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/hooks/useRemount.ts b/src/hooks/useRemount.ts index a88d317b4..c1d138048 100644 --- a/src/hooks/useRemount.ts +++ b/src/hooks/useRemount.ts @@ -1,11 +1,16 @@ import { useEffect, useState } from "react" import { usePrevious } from "react-use" -export const useRemount = (trigger: boolean) => { +export const useRemount = ( + triggers: T[], +) => { const [version, setVersion] = useState(0) - const prevTriggerValue = usePrevious(trigger) + const prevTriggersValue = usePrevious(triggers) - const isChanged = !!prevTriggerValue !== trigger + const isChanged = + prevTriggersValue !== undefined + ? triggers.some((trigger, i) => prevTriggersValue[i] !== trigger) + : false useEffect(() => { if (isChanged) { diff --git a/src/sections/trade/sections/swap/SwapPage.tsx b/src/sections/trade/sections/swap/SwapPage.tsx index 3210eef81..462c2f5e3 100644 --- a/src/sections/trade/sections/swap/SwapPage.tsx +++ b/src/sections/trade/sections/swap/SwapPage.tsx @@ -15,6 +15,9 @@ import { useDisplayAssetStore } from "utils/displayAsset" import { isEvmAccount } from "utils/evm" import { NATIVE_ASSET_ID } from "utils/api" import { useRemount } from "hooks/useRemount" +import { AddTokenModal } from "sections/wallet/addToken/modal/AddTokenModal" +import { useState } from "react" +import { useUserExternalTokenStore } from "sections/wallet/addToken/AddToken.utils" const defaultEvmTokenId: string = import.meta.env.VITE_EVM_NATIVE_ASSET_ID @@ -26,6 +29,7 @@ const SwapApp = createComponent({ onTxNew: "gc:tx:new" as EventName>, onDcaSchedule: "gc:tx:scheduleDca" as EventName>, onDcaTerminate: "gc:tx:terminateDca" as EventName>, + onNewAssetClick: "gc:newAsset" as EventName>, }, }) @@ -54,9 +58,12 @@ export function SwapPage() { const { account } = useAccount() const { createTransaction } = useStore() const { stableCoinId } = useDisplayAssetStore() + const [addToken, setAddToken] = useState(false) + + const { tokens: externalTokensStored } = useUserExternalTokenStore.getState() const isEvm = isEvmAccount(account?.address) - const version = useRemount(isEvm) + const version = useRemount([isEvm, externalTokensStored.length]) const preference = useProviderRpcUrlStore() const rpcUrl = preference.rpcUrl ?? import.meta.env.VITE_PROVIDER_URL @@ -119,6 +126,7 @@ export function SwapPage() { if (r) { r.setAttribute("chart", "") r.setAttribute("twapOn", "") + r.setAttribute("newAssetBtn", "") } }} assetIn={assetIn} @@ -134,7 +142,9 @@ export function SwapPage() { onTxNew={(e) => handleSubmit(e)} onDcaSchedule={(e) => handleSubmit(e)} onDcaTerminate={(e) => handleSubmit(e)} + onNewAssetClick={() => setAddToken(true)} /> + {addToken && setAddToken(false)} />} ) } From d1124ca88c27d78a27e3010e9f82a9ca62dff287 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Wed, 17 Apr 2024 09:56:04 +0200 Subject: [PATCH 036/103] Address PR comments --- .../pools/farms/modals/join/JoinFarmsModal.utils.ts | 5 +++-- src/sections/pools/header/MyLiquidityTotal.tsx | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts b/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts index 6e63c5b70..0720b77ea 100644 --- a/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts +++ b/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts @@ -7,9 +7,10 @@ import { BN_0 } from "utils/constants" import { Farm } from "api/farms" import { useMemo } from "react" import { scale, scaleHuman } from "utils/balance" -import i18n from "i18next" +import { useTranslation } from "react-i18next" export const useZodSchema = (id: string, farms: Farm[]) => { + const { t } = useTranslation() const { account } = useAccount() const { assets } = useRpcProvider() const { data: balance } = useTokenBalance(id, account?.address) @@ -31,7 +32,7 @@ export const useZodSchema = (id: string, farms: Farm[]) => { .pipe(maxBalance(balance?.balance ?? BN_0, meta.decimals)) .refine( (value) => scale(value, meta.decimals).gte(minDeposit), - i18n.t("farms.modal.join.minDeposit", { + t("farms.modal.join.minDeposit", { value: scaleHuman(minDeposit, meta.decimals), }), ), diff --git a/src/sections/pools/header/MyLiquidityTotal.tsx b/src/sections/pools/header/MyLiquidityTotal.tsx index 349f5ef10..5496bfafc 100644 --- a/src/sections/pools/header/MyLiquidityTotal.tsx +++ b/src/sections/pools/header/MyLiquidityTotal.tsx @@ -14,11 +14,11 @@ export const MyLiquidityTotal = () => { const omnipoolPositions = useOmnipoolPositionsData() const totalFarms = useFarmDepositsTotal() const stablePoolTotal = useMyStablePoolaTotal() - const xylPools = useXYKPools(true) + const xykPools = useXYKPools(true) const xykTotal = useMemo(() => { - if (xylPools.data) { - return xylPools.data.reduce((acc, xykPool) => { + if (xykPools.data) { + return xykPools.data.reduce((acc, xykPool) => { const myTotalDisplay = xykPool.tvlDisplay ?.div(100) .times(xykPool.shareTokenIssuance?.myPoolShare ?? 1) @@ -27,7 +27,7 @@ export const MyLiquidityTotal = () => { }, BN_0) } return BN_0 - }, [xylPools.data]) + }, [xykPools.data]) const totalOmnipool = useMemo(() => { return omnipoolPositions.data.reduce((acc, position) => { @@ -45,7 +45,7 @@ export const MyLiquidityTotal = () => { isLoading={ omnipoolPositions.isInitialLoading || stablePoolTotal.isLoading || - xylPools.isInitialLoading || + xykPools.isInitialLoading || totalFarms.isLoading } value={total} From 2ffde4a0113978dd36d9a3e79d18b60eca38c4ea Mon Sep 17 00:00:00 2001 From: vkulinich Date: Wed, 17 Apr 2024 11:52:22 +0200 Subject: [PATCH 037/103] Fix joining extra farms --- .../farms/modals/join/JoinFarmsButton.tsx | 12 ++- .../farms/modals/join/JoinFarmsModal.tsx | 15 ++-- .../farms/modals/join/JoinFarmsModal.utils.ts | 24 +++--- .../joinedFarmDetails/JoinedFarmsDetails.tsx | 37 ++++------ .../position/redeposit/RedepositFarms.tsx | 10 ++- src/utils/farms/deposit.tsx | 10 ++- src/utils/farms/redeposit.ts | 45 ------------ src/utils/farms/redeposit.tsx | 73 +++++++++++++++++++ 8 files changed, 133 insertions(+), 93 deletions(-) delete mode 100644 src/utils/farms/redeposit.ts create mode 100644 src/utils/farms/redeposit.tsx diff --git a/src/sections/pools/farms/modals/join/JoinFarmsButton.tsx b/src/sections/pools/farms/modals/join/JoinFarmsButton.tsx index 4028f8847..b78765648 100644 --- a/src/sections/pools/farms/modals/join/JoinFarmsButton.tsx +++ b/src/sections/pools/farms/modals/join/JoinFarmsButton.tsx @@ -7,6 +7,7 @@ import { useAccount } from "sections/web3-connect/Web3Connect.utils" import FPIcon from "assets/icons/PoolsAndFarms.svg?react" import { JoinFarmModal } from "sections/pools/farms/modals/join/JoinFarmsModal" import { HydraPositionsTableData } from "sections/wallet/assets/hydraPositions/WalletAssetsHydraPositions.utils" +import { useFarmDepositMutation } from "utils/farms/deposit" export const JoinFarmsButton = (props: { poolId: string @@ -18,6 +19,14 @@ export const JoinFarmsButton = (props: { const [joinFarm, setJoinFarm] = useState(false) const farms = useFarms([props.poolId]) + const mutation = useFarmDepositMutation( + props.poolId, + props.position?.id ?? "", + farms.data, + () => setJoinFarm(false), + props.onSuccess, + ) + return ( <> From 62f5ec652a60c7faed3f6630d62c3ce801c22b1a Mon Sep 17 00:00:00 2001 From: vkulinich Date: Fri, 19 Apr 2024 16:01:00 +0200 Subject: [PATCH 050/103] External tokens additional information --- src/api/assetDetails.ts | 1 + src/api/externalAssetRegistry.ts | 58 ++++++ src/api/provider.ts | 1 + src/assets/icons/WarningIconRed.svg | 3 + src/i18n/locales/en/translations.json | 14 ++ src/providers/rpcProvider.tsx | 6 +- src/sections/pools/header/VolumeTotal.tsx | 18 +- .../addToken/modal/AddTokenFormModal.tsx | 7 +- .../components/TokenInfo/TokenInfo.styled.ts | 9 + .../modal/components/TokenInfo/TokenInfo.tsx | 176 ++++++++++++++++++ .../components/TokenInfo/TokenInfo.utils.ts | 124 ++++++++++++ 11 files changed, 413 insertions(+), 4 deletions(-) create mode 100644 src/assets/icons/WarningIconRed.svg create mode 100644 src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.styled.ts create mode 100644 src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.tsx create mode 100644 src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.utils.ts diff --git a/src/api/assetDetails.ts b/src/api/assetDetails.ts index bb3139857..f14c8e9df 100644 --- a/src/api/assetDetails.ts +++ b/src/api/assetDetails.ts @@ -494,6 +494,7 @@ export const getAssets = async (api: ApiPromise) => { hub, rawTradeAssets, }, + poolService, tradeRouter, featureFlags: { referrals: !!isReferralsEnabled, diff --git a/src/api/externalAssetRegistry.ts b/src/api/externalAssetRegistry.ts index 0345b72d9..359f826b0 100644 --- a/src/api/externalAssetRegistry.ts +++ b/src/api/externalAssetRegistry.ts @@ -2,6 +2,20 @@ import { useQuery } from "@tanstack/react-query" import { QUERY_KEYS } from "utils/queryKeys" import { chainsMap } from "@galacticcouncil/xcm-cfg" import { SubstrateApis } from "@galacticcouncil/xcm-sdk" +import { + ASSET_HUB_ID, + TExternalAsset, +} from "sections/wallet/addToken/AddToken.utils" + +type TRegistryChain = { + assetCnt: string + id: string + paraID: number + relayChain: "polkadot" | "kusama" + data: (TExternalAsset & { currencyID: string })[] +} + +const HYDRA_PARACHAIN_ID = 2034 export const getAssetHubAssets = async () => { const parachain = chainsMap.get("assethub") @@ -76,3 +90,47 @@ export const useAssetHubAssetRegistry = () => { }, ) } + +export const usePolkadotRegistry = () => { + return useQuery(["polkadotRegistry"], async () => { + const res = await fetch( + "https://cdn.jsdelivr.net/gh/colorfulnotion/xcm-global-registry/metadata/xcmgar.json", + ) + const data = await res.json() + let polkadotAssets: TRegistryChain[] = [] + + try { + polkadotAssets = data.assets.polkadot ?? [] + } catch (error) {} + + return polkadotAssets + }) +} + +export const useParachainAmount = (id: string) => { + const chains = usePolkadotRegistry() + + const validChains = chains.data?.reduce((acc, chain) => { + // skip asst hub and hydra chains + if (chain.paraID === ASSET_HUB_ID || chain.paraID === HYDRA_PARACHAIN_ID) + return acc + + const assets = chain.data + + const isAsset = assets.some((asset) => { + try { + return asset.currencyID === id + } catch (error) { + return false + } + }) + + if (isAsset) { + acc.push(chain) + } + + return acc + }, []) + + return { chains: validChains ?? [], amount: validChains?.length ?? 0 } +} diff --git a/src/api/provider.ts b/src/api/provider.ts index 6aba664c5..29735fa0e 100644 --- a/src/api/provider.ts +++ b/src/api/provider.ts @@ -152,6 +152,7 @@ export const useProviderData = (rpcUrl: string) => { assets: assets.assets, tradeRouter: assets.tradeRouter, featureFlags: assets.featureFlags, + poolService: assets.poolService, } }, { refetchOnWindowFocus: false }, diff --git a/src/assets/icons/WarningIconRed.svg b/src/assets/icons/WarningIconRed.svg new file mode 100644 index 000000000..94cefb96b --- /dev/null +++ b/src/assets/icons/WarningIconRed.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/i18n/locales/en/translations.json b/src/i18n/locales/en/translations.json index 24b892d4a..12e44c47a 100644 --- a/src/i18n/locales/en/translations.json +++ b/src/i18n/locales/en/translations.json @@ -1,4 +1,6 @@ { + "no": "No", + "yes": "Yes", "and": "and", "apr": "APR", "back": "Back", @@ -513,6 +515,18 @@ "wallet.addToken.form.multilocation.label": "Multilocation", "wallet.addToken.form.button.register.hydra": "Register on Hydra", "wallet.addToken.form.button.register.forMe": "Add to my UI", + "wallet.addToken.form.info": { + "title":"Additional data", + "registered": "Asset registered on Hydra", + "registered.tooltip": "Asset {{value}} registered on HydraDx", + "masterAccount": "Master account key existing", + "masterAccount.tooltip": "The creator of this asset has not revoked their admin rights. This means the supply can be minted, burned or frozen at any point. Proceed at your own risk.", + "availability": "Available on other parachains", + "availability.tooltip_one": "This asset is also registered on {{count}} another parachain.", + "availability.tooltip_other": "This asset is also registered on {{count}} other parachains.", + "isolatedPool": "Isolated Pool created", + "volume": "Daily volume on HydraDX" + }, "wallet.addToken.toast.register.onLoading": "Registering {{name}} on HydraDx as external asset", "wallet.addToken.toast.register.onSuccess": "You registered {{name}} as external asset", "wallet.addToken.toast.add.onSuccess": "You added info about {{name}} to your UI", diff --git a/src/providers/rpcProvider.tsx b/src/providers/rpcProvider.tsx index 940df8c6b..89a0eb249 100644 --- a/src/providers/rpcProvider.tsx +++ b/src/providers/rpcProvider.tsx @@ -1,4 +1,4 @@ -import { TradeRouter } from "@galacticcouncil/sdk" +import { TradeRouter, PoolService } from "@galacticcouncil/sdk" import { ApiPromise } from "@polkadot/api" import { TAsset, @@ -28,6 +28,7 @@ type TProviderContext = { api: ApiPromise assets: IContextAssets tradeRouter: TradeRouter + poolService: PoolService isLoaded: boolean featureFlags: Awaited>["featureFlags"] } @@ -37,6 +38,7 @@ const ProviderContext = createContext({ assets: {} as TProviderContext["assets"], tradeRouter: {} as TradeRouter, featureFlags: {} as TProviderContext["featureFlags"], + poolService: {} as TProviderContext["poolService"], }) export const useRpcProvider = () => useContext(ProviderContext) @@ -116,6 +118,7 @@ export const RpcProvider = ({ children }: { children: ReactNode }) => { getAssets, tradeAssets, }, + poolService: providerData.data.poolService, api: providerData.data.api, tradeRouter: providerData.data.tradeRouter, featureFlags: providerData.data.featureFlags, @@ -128,6 +131,7 @@ export const RpcProvider = ({ children }: { children: ReactNode }) => { assets: {} as TProviderContext["assets"], tradeRouter: {} as TradeRouter, featureFlags: {} as TProviderContext["featureFlags"], + poolService: {} as TProviderContext["poolService"], } }, [preference._hasHydrated, providerData.data]) diff --git a/src/sections/pools/header/VolumeTotal.tsx b/src/sections/pools/header/VolumeTotal.tsx index a6a755283..78290765b 100644 --- a/src/sections/pools/header/VolumeTotal.tsx +++ b/src/sections/pools/header/VolumeTotal.tsx @@ -3,10 +3,18 @@ import { useXYKPoolTradeVolumes } from "sections/pools/pool/details/PoolDetails. import { BN_0 } from "utils/constants" import { HeaderTotalData } from "./PoolsHeaderTotal" import { usePools } from "sections/pools/PoolsPage.utils" +import { useRpcProvider } from "providers/rpcProvider" export const AllPoolsVolumeTotal = () => { + const { assets } = useRpcProvider() const xykPools = useGetXYKPools() - const poolsAddress = xykPools.data?.map((pool) => pool.poolAddress) ?? [] + const poolsAddress = + xykPools.data + ?.filter((pool) => + assets.getAssets(pool.assets).every((asset) => asset.symbol), + ) + .map((pool) => pool.poolAddress) ?? [] + const xykVolumes = useXYKPoolTradeVolumes(poolsAddress) const pools = usePools() @@ -41,8 +49,14 @@ export const AllPoolsVolumeTotal = () => { } export const XYKVolumeTotal = () => { + const { assets } = useRpcProvider() const pools = useGetXYKPools() - const poolsAddress = pools.data?.map((pool) => pool.poolAddress) ?? [] + const poolsAddress = + pools.data + ?.filter((pool) => + assets.getAssets(pool.assets).every((asset) => asset.symbol), + ) + .map((pool) => pool.poolAddress) ?? [] const xykVolumes = useXYKPoolTradeVolumes(poolsAddress) const isLoading = pools.isInitialLoading || xykVolumes.isLoading diff --git a/src/sections/wallet/addToken/modal/AddTokenFormModal.tsx b/src/sections/wallet/addToken/modal/AddTokenFormModal.tsx index 443ec845f..7b34f4ee4 100644 --- a/src/sections/wallet/addToken/modal/AddTokenFormModal.tsx +++ b/src/sections/wallet/addToken/modal/AddTokenFormModal.tsx @@ -17,6 +17,7 @@ import { Spacer } from "components/Spacer/Spacer" import { useToast } from "state/toasts" import { useRefetchProviderData } from "api/provider" import { InputBox } from "components/Input/InputBox" +import { TokenInfo } from "./components/TokenInfo/TokenInfo" type Props = { asset: TExternalAsset @@ -153,7 +154,11 @@ export const AddTokenFormModal: FC = ({ asset, onClose }) => { )} /> - + + + + + {isChainStored ? ( From 11a63ff0537b5edf6679b7c66b0f04cdc0100658 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Wed, 24 Apr 2024 15:58:26 +0200 Subject: [PATCH 070/103] add master key white list --- .../modal/components/TokenInfo/TokenInfo.tsx | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.tsx b/src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.tsx index 99c10d8c9..f719bbc98 100644 --- a/src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.tsx +++ b/src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.tsx @@ -17,6 +17,8 @@ import WarningIcon from "assets/icons/WarningIconRed.svg?react" import { Icon } from "components/Icon/Icon" import BN from "bignumber.js" +const MASTER_KEY_WHITELIST = ["23", "31337", "42069"] + export const TokenInfo = ({ asset, isChainStored, @@ -96,10 +98,19 @@ export const TokenInfo = ({
- - {t("yes")} - - } /> + {MASTER_KEY_WHITELIST.some((id) => id === asset.id) ? ( + + {t("no")} + + ) : ( + <> + {" "} + + {t("yes")} + + } /> + + )}
From b76a2f735d8f13f6a6b66449b21ebb68ee153ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Wed, 24 Apr 2024 16:15:21 +0200 Subject: [PATCH 071/103] Fix non partial OTC order submit reload --- src/sections/trade/sections/otc/modals/FillOrder.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sections/trade/sections/otc/modals/FillOrder.tsx b/src/sections/trade/sections/otc/modals/FillOrder.tsx index d3bf89b88..485263c74 100644 --- a/src/sections/trade/sections/otc/modals/FillOrder.tsx +++ b/src/sections/trade/sections/otc/modals/FillOrder.tsx @@ -2,7 +2,7 @@ import { useTokenBalance } from "api/balances" import { Button } from "components/Button/Button" import { Modal } from "components/Modal/Modal" import { Text } from "components/Typography/Text/Text" -import { useState } from "react" +import { FormEvent, useState } from "react" import { Trans, useTranslation } from "react-i18next" import { BN_10 } from "utils/constants" import { useStore } from "state/store" @@ -40,7 +40,8 @@ export const FillOrder = ({ const price = accepting.amount.div(offering.amount) - const handleSubmit = async () => { + const handleSubmit = async (e: FormEvent) => { + e.preventDefault() if (assetInMeta.decimals == null) throw new Error("Missing assetIn meta") if (assetInBalance.data?.balance == null) From b4b560db2be93dc44dcc72df82d8f2e7e62d127c Mon Sep 17 00:00:00 2001 From: vkulinich Date: Wed, 24 Apr 2024 17:20:37 +0200 Subject: [PATCH 072/103] address comments --- .../components/TokenInfo/TokenInfo.utils.ts | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.utils.ts b/src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.utils.ts index 2197d6365..9dd556d24 100644 --- a/src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.utils.ts +++ b/src/sections/wallet/addToken/modal/components/TokenInfo/TokenInfo.utils.ts @@ -1,7 +1,8 @@ +import { useQuery } from "@tanstack/react-query" import { useAssetHubAssetRegistry } from "api/externalAssetRegistry" import { getXYKVolumeAssetTotalValue, useXYKTradeVolumes } from "api/volume" import { useRpcProvider } from "providers/rpcProvider" -import { useEffect, useMemo, useState } from "react" +import { useMemo, useState } from "react" import { useUserExternalTokenStore } from "sections/wallet/addToken/AddToken.utils" import { BN_0 } from "utils/constants" import { useDisplayPrices } from "utils/displayAsset" @@ -68,19 +69,23 @@ export const useExternalXYKVolume = (poolsAddress: string[]) => { ] const missingAssets = useMissingExternalAssets(allAssetsInPools) - - useEffect(() => { - const syncToken = async () => { - if (missingAssets.length && !valid) { - await poolService.syncRegistry([ - ...externalTokensStored, - ...missingAssets, - ]) + useQuery( + ["syncExternalTokens", missingAssets.map((asset) => asset.id).join(",")], + async () => { + await poolService.syncRegistry([ + ...externalTokensStored, + ...missingAssets, + ]) + + return true + }, + { + onSuccess: () => { setValid(true) - } - } - syncToken() - }, [externalTokensStored, missingAssets, poolService, valid]) + }, + enabled: !valid && !!missingAssets.length, + }, + ) const spotPrices = useDisplayPrices(valid ? allAssetsInPools : []) From 16196a30b3514b2afe15c88ff47f5d7a2b5da473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Wed, 24 Apr 2024 17:37:21 +0200 Subject: [PATCH 073/103] OTC order form reworked --- .../AssetInput/AssetInput.styled.ts | 1 + src/components/AssetSelect/AssetSelect.tsx | 1 + .../AssetSelect/AssetSelectButton.tsx | 4 +- .../trade/sections/otc/modals/FillOrder.tsx | 23 +- .../sections/otc/modals/PartialFillOrder.tsx | 77 +++--- .../otc/modals/PartialFillOrder.utils.tsx | 27 ++ .../sections/otc/modals/cmp/AssetPrice.tsx | 31 --- .../sections/otc/modals/cmp/AssetSelect.tsx | 243 +++++------------- .../transfer/WalletTransferAssetSelect.tsx | 4 + 9 files changed, 151 insertions(+), 260 deletions(-) create mode 100644 src/sections/trade/sections/otc/modals/PartialFillOrder.utils.tsx delete mode 100644 src/sections/trade/sections/otc/modals/cmp/AssetPrice.tsx diff --git a/src/components/AssetInput/AssetInput.styled.ts b/src/components/AssetInput/AssetInput.styled.ts index 28d431fbc..25dca3f54 100644 --- a/src/components/AssetInput/AssetInput.styled.ts +++ b/src/components/AssetInput/AssetInput.styled.ts @@ -50,6 +50,7 @@ export const SInput = styled.input` line-height: 24px; text-align: right; font-weight: 600; + font-family: "ChakraPetchSemiBold"; padding: 0; diff --git a/src/components/AssetSelect/AssetSelect.tsx b/src/components/AssetSelect/AssetSelect.tsx index fe58e6558..fb7df82b3 100644 --- a/src/components/AssetSelect/AssetSelect.tsx +++ b/src/components/AssetSelect/AssetSelect.tsx @@ -134,6 +134,7 @@ export const AssetSelect = (props: { void assetId: string + className?: string } -export const AssetSelectButton = ({ onClick, assetId }: Props) => { +export const AssetSelectButton = ({ onClick, assetId, className }: Props) => { const { t } = useTranslation() const { assets } = useRpcProvider() const asset = assets.getAsset(assetId) @@ -46,6 +47,7 @@ export const AssetSelectButton = ({ onClick, assetId }: Props) => { return ( { e.preventDefault() diff --git a/src/sections/trade/sections/otc/modals/FillOrder.tsx b/src/sections/trade/sections/otc/modals/FillOrder.tsx index d3bf89b88..998082eb5 100644 --- a/src/sections/trade/sections/otc/modals/FillOrder.tsx +++ b/src/sections/trade/sections/otc/modals/FillOrder.tsx @@ -2,15 +2,15 @@ import { useTokenBalance } from "api/balances" import { Button } from "components/Button/Button" import { Modal } from "components/Modal/Modal" import { Text } from "components/Typography/Text/Text" -import { useState } from "react" +import { FormEvent, useState } from "react" import { Trans, useTranslation } from "react-i18next" -import { BN_10 } from "utils/constants" +import { BN_1, BN_10 } from "utils/constants" import { useStore } from "state/store" import { OfferingPair } from "sections/trade/sections/otc/orders/OtcOrdersData.utils" -import { OrderAssetPrice } from "./cmp/AssetPrice" import { OrderAssetGet, OrderAssetPay } from "./cmp/AssetSelect" import { useRpcProvider } from "providers/rpcProvider" import { useAccount } from "sections/web3-connect/Web3Connect.utils" +import { TokensConversion } from "sections/pools/modals/AddLiquidity/components/TokensConvertion/TokensConversion" type FillOrderProps = { orderId: string @@ -40,7 +40,8 @@ export const FillOrder = ({ const price = accepting.amount.div(offering.amount) - const handleSubmit = async () => { + const handleSubmit = async (e: FormEvent) => { + e.preventDefault() if (assetInMeta.decimals == null) throw new Error("Missing assetIn meta") if (assetInBalance.data?.balance == null) @@ -128,10 +129,16 @@ export const FillOrder = ({ readonly={true} error={error} /> - ({ + mode: "onChange", defaultValues: { free: accepting.amount, }, + resolver: zodResolver(formSchema), }) - useEffect(() => { - form.trigger() - }, [form]) - - const { api, assets } = useRpcProvider() - const assetInMeta = assets.getAsset(accepting.asset) - const assetInBalance = useTokenBalance(accepting.asset, account?.address) - const assetOutMeta = assets.getAsset(offering.asset) - const { createTransaction } = useStore() const price = accepting.amount.div(offering.amount) @@ -63,14 +68,14 @@ export const PartialFillOrder = ({ const handlePayWithChange = () => { const { amountOut } = form.getValues() const amountIn = new BigNumber(amountOut).multipliedBy(price) - form.setValue("amountIn", amountIn.toFixed()) + form.setValue("amountIn", !amountIn.isNaN() ? amountIn.toFixed() : "") form.trigger() } const handleYouGetChange = () => { const { amountIn } = form.getValues() const amountOut = new BigNumber(amountIn).div(price) - form.setValue("amountOut", amountOut.toFixed()) + form.setValue("amountOut", !amountOut.isNaN() ? amountOut.toFixed() : "") form.trigger() } @@ -197,25 +202,6 @@ export const PartialFillOrder = ({ { - const balance = assetInBalance.data?.balance - const decimals = assetInMeta.decimals.toString() - if ( - balance && - decimals && - balance.gte( - new BigNumber(value).multipliedBy(BN_10.pow(decimals)), - ) - ) { - return true - } - return t("otc.order.fill.validation.notEnoughBalance") - }, - }, - }} render={({ field: { name, value, onChange }, fieldState: { error }, @@ -235,25 +221,20 @@ export const PartialFillOrder = ({ /> )} /> - { - if (offering.amount.gte(new BigNumber(value))) { - return true - } - return t("otc.order.fill.validation.orderTooBig") - }, - }, - }} render={({ field: { name, value, onChange }, fieldState: { error }, diff --git a/src/sections/trade/sections/otc/modals/PartialFillOrder.utils.tsx b/src/sections/trade/sections/otc/modals/PartialFillOrder.utils.tsx new file mode 100644 index 000000000..f0b9eb78e --- /dev/null +++ b/src/sections/trade/sections/otc/modals/PartialFillOrder.utils.tsx @@ -0,0 +1,27 @@ +import { required, maxBalance } from "utils/validators" +import * as z from "zod" +import BigNumber from "bignumber.js" +import { useTranslation } from "react-i18next" + +export const usePartialFillFormSchema = ({ + offeringAmount, + assetInBalance, + assetInDecimals, +}: { + offeringAmount: BigNumber + assetInBalance: BigNumber + assetInDecimals: number +}) => { + const { t } = useTranslation() + return z.object({ + amountIn: required.pipe(maxBalance(assetInBalance, assetInDecimals)), + amountOut: required.pipe( + z + .string() + .refine( + (value) => offeringAmount.gte(new BigNumber(value)), + t("otc.order.fill.validation.orderTooBig"), + ), + ), + }) +} diff --git a/src/sections/trade/sections/otc/modals/cmp/AssetPrice.tsx b/src/sections/trade/sections/otc/modals/cmp/AssetPrice.tsx deleted file mode 100644 index 2e04de8f8..000000000 --- a/src/sections/trade/sections/otc/modals/cmp/AssetPrice.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import * as React from "react" -import * as UI from "@galacticcouncil/ui" -import { createComponent } from "@lit-labs/react" -import { SContainer, SDivider, SPrice } from "./AssetPrice.styled" - -export const UigcAssetPrice = createComponent({ - tagName: "uigc-asset-price", - elementClass: UI.AssetPrice, - react: React, -}) - -export function OrderAssetPrice(props: { - inputAsset: string | undefined - outputAsset: string | undefined - price: string -}) { - return ( - - - {props.price && ( - - - - )} - - ) -} diff --git a/src/sections/trade/sections/otc/modals/cmp/AssetSelect.tsx b/src/sections/trade/sections/otc/modals/cmp/AssetSelect.tsx index a153942fc..2ccad4c40 100644 --- a/src/sections/trade/sections/otc/modals/cmp/AssetSelect.tsx +++ b/src/sections/trade/sections/otc/modals/cmp/AssetSelect.tsx @@ -1,43 +1,8 @@ import * as React from "react" -import * as UI from "@galacticcouncil/ui" -import { createComponent, EventName } from "@lit-labs/react" import { u32 } from "@polkadot/types" import BN from "bignumber.js" -import { useRpcProvider } from "providers/rpcProvider" - -export const UigcAsset = createComponent({ - tagName: "uigc-asset", - elementClass: UI.Asset, - react: React, -}) - -export const UigcAssetId = createComponent({ - tagName: "uigc-asset-id", - elementClass: UI.AssetId, - react: React, -}) - -export const UigcAssetTransfer = createComponent({ - tagName: "uigc-asset-transfer", - elementClass: UI.AssetTransfer, - react: React, - events: { - onAssetInputChange: "asset-input-change" as EventName, - onAssetSelectorClick: "asset-selector-click" as EventName, - }, -}) - -export const UigcAssetBalance = createComponent({ - tagName: "uigc-asset-balance", - elementClass: UI.AssetBalance, - react: React, -}) - -export const UigcButton = createComponent({ - tagName: "uigc-button", - elementClass: UI.Button, - react: React, -}) +import { WalletTransferAssetSelect } from "sections/wallet/transfer/WalletTransferAssetSelect" +import { Button } from "components/Button/Button" export function OrderAssetSelect(props: { name: string @@ -49,54 +14,16 @@ export function OrderAssetSelect(props: { onOpen: () => void error?: string }) { - const { assets } = useRpcProvider() - const asset = props.asset - ? assets.getAsset(props.asset.toString()) - : undefined - - const assetIcon = - asset && assets.isBond(asset) - ? assets.getAsset(asset.assetId)?.symbol - : asset?.symbol - - const assetBalance = props.balance - const assetDecimals = asset?.decimals - - let blnc: string = "" - if (assetBalance && assetDecimals) { - blnc = assetBalance.shiftedBy(-1 * assetDecimals).toFixed() - } - return ( - { - if (!el) { - return - } - - if (props.error) { - el.setAttribute("error", props.error) - } else { - el.removeAttribute("error") - } - }} - onAssetInputChange={(e) => props.onChange(e.detail.value)} - onAssetSelectorClick={props.onOpen} - id={props.name} + - - - - props.onChange(blnc)} - /> - + asset={props.asset?.toString() ?? ""} + error={props.error} + onChange={(value) => (props.onChange ? props.onChange(value) : undefined)} + onAssetOpen={props.onOpen} + /> ) } @@ -110,49 +37,17 @@ export function OrderAssetPay(props: { error?: string readonly?: boolean }) { - const { assets } = useRpcProvider() - const asset = assets.getAsset(props.asset.toString()) - const assetIcon = assets.isBond(asset) - ? assets.getAsset(asset.assetId)?.symbol - : asset?.symbol - - const assetBalance = props.balance - const assetDecimals = asset.decimals - - let blnc: string = "" - if (assetBalance && assetDecimals) { - blnc = assetBalance.shiftedBy(-1 * assetDecimals).toFixed() - } - return ( - { - if (!el) { - return - } - props.readonly && el.setAttribute("readonly", "") - if (props.error) { - el.setAttribute("error", props.error) - } else { - el.removeAttribute("error") - } - }} - onAssetInputChange={(e) => - props.onChange && props.onChange(e.detail.value) - } - id={props.name} + - - - - - + asset={props.asset.toString()} + disabled={props.readonly} + error={props.error} + withoutMaxBtn + onChange={(value) => (props.onChange ? props.onChange(value) : undefined)} + /> ) } @@ -160,21 +55,22 @@ function getPercentageValue(value: BN, pct: number): BN { return value.div(100).multipliedBy(new BN(pct)) } -const OrderAssetPctBtn = ( - pct: number, - remaining: BN, - onClick: (value: string) => void, -) => ( - void +}> = ({ pct, remaining, onClick }) => ( + ) export function OrderAssetGet(props: { @@ -187,48 +83,51 @@ export function OrderAssetGet(props: { error?: string readonly?: boolean }) { - const { assets } = useRpcProvider() - const asset = assets.getAsset(props.asset.toString()) - const assetIcon = assets.isBond(asset) - ? assets.getAsset(asset.assetId)?.symbol - : asset?.symbol - return ( - { - if (!el) { - return - } - props.readonly && el.setAttribute("readonly", "") - - if (props.error) { - el.setAttribute("error", props.error) - } else { - el.removeAttribute("error") - } - }} - onAssetInputChange={(e) => - props.onChange && props.onChange(e.detail.value) - } - id={props.name} - title={props.title} - asset={asset.symbol} - unit={asset.symbol} - amount={props.value} - selectable={false} - readonly={props.readonly || false} - > - - - +
+
+ + props.onChange ? props.onChange(value) : undefined + } + /> +
{props.onChange && ( -
- {OrderAssetPctBtn(25, props.remaining, props.onChange)} - {OrderAssetPctBtn(50, props.remaining, props.onChange)} - {OrderAssetPctBtn(75, props.remaining, props.onChange)} - {OrderAssetPctBtn(100, props.remaining, props.onChange)} +
+ + + +
)} - +
) } diff --git a/src/sections/wallet/transfer/WalletTransferAssetSelect.tsx b/src/sections/wallet/transfer/WalletTransferAssetSelect.tsx index 05a004a16..c7872c83c 100644 --- a/src/sections/wallet/transfer/WalletTransferAssetSelect.tsx +++ b/src/sections/wallet/transfer/WalletTransferAssetSelect.tsx @@ -20,6 +20,8 @@ export const WalletTransferAssetSelect = (props: { balance?: BN balanceMax?: BN withoutMaxBtn?: boolean + withoutMaxValue?: boolean + disabled?: boolean error?: string }) => { @@ -42,6 +44,8 @@ export const WalletTransferAssetSelect = (props: { error={props.error} balanceLabel={t("selectAsset.balance.label")} withoutMaxBtn={props.withoutMaxBtn} + withoutMaxValue={props.withoutMaxValue} + disabled={props.disabled} /> ) } From 07b7bbdf7f8a1a35e32ce935dd83c056af542e83 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Thu, 25 Apr 2024 12:15:34 +0200 Subject: [PATCH 074/103] Update xcm-cfg --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 174a5c4a3..707e0a0bd 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@galacticcouncil/math-xyk": "^0.2.0", "@galacticcouncil/sdk": "^2.2.3", "@galacticcouncil/ui": "^3.1.12", - "@galacticcouncil/xcm-cfg": "^1.11.5", + "@galacticcouncil/xcm-cfg": "^1.11.6", "@galacticcouncil/xcm-sdk": "^2.4.0", "@hookform/resolvers": "^3.3.4", "@lit-labs/react": "^1.1.0", diff --git a/yarn.lock b/yarn.lock index d860f4e68..ce6b811f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3087,10 +3087,10 @@ lit "^2.5.0" ts-debounce "^4.0.0" -"@galacticcouncil/xcm-cfg@^1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@galacticcouncil/xcm-cfg/-/xcm-cfg-1.11.5.tgz#d182eae63d94c2b156f7c210bf32d05f0b978400" - integrity sha512-LHbDXb3lejiplWIwPupIu8fHCjVbomZ0+lMucwwrA4kR7BlkW50mfDVzdI7u/xu/FoF+xr37e7FIK6Lb1Td8Pw== +"@galacticcouncil/xcm-cfg@^1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@galacticcouncil/xcm-cfg/-/xcm-cfg-1.11.6.tgz#ed5a0caeeb92d2bfcb331a00cfe91edf3b13d895" + integrity sha512-xnH166yQIVNX0xiXq0hekz+lHxFcZxsVH3mOHvg0uJ5RE80b3FkQDOV5Xb1YyqtJrrcldhzAG1Z8DSMw/Ef1dw== "@galacticcouncil/xcm-sdk@^2.4.0": version "2.4.0" From a8cf97e08a3165bb8e39207d6e4ed25502e7aa48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Thu, 25 Apr 2024 13:38:22 +0200 Subject: [PATCH 075/103] Update pkgs --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 707e0a0bd..81e9ed974 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@galacticcouncil/math-staking": "^0.2.0", "@galacticcouncil/math-xyk": "^0.2.0", "@galacticcouncil/sdk": "^2.2.3", - "@galacticcouncil/ui": "^3.1.12", + "@galacticcouncil/ui": "^3.1.13", "@galacticcouncil/xcm-cfg": "^1.11.6", "@galacticcouncil/xcm-sdk": "^2.4.0", "@hookform/resolvers": "^3.3.4", diff --git a/yarn.lock b/yarn.lock index ce6b811f0..4688bdbef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3076,10 +3076,10 @@ bignumber.js "^9.1.0" lodash.clonedeep "^4.5.0" -"@galacticcouncil/ui@^3.1.12": - version "3.1.12" - resolved "https://registry.yarnpkg.com/@galacticcouncil/ui/-/ui-3.1.12.tgz#ccbfb3f4632308b1964c6531bc31fe9eae3f1a06" - integrity sha512-jD5BDI5VKR1QCACXqxlVDFPwaM5Uh74qHToXr8nfpCO6j1dbrIZWzp1OvqKkFfKK145Us22FDPRRNxNa51vGaw== +"@galacticcouncil/ui@^3.1.13": + version "3.1.13" + resolved "https://registry.yarnpkg.com/@galacticcouncil/ui/-/ui-3.1.13.tgz#6a59a591de4dce05a9e094b226784b2072fcc590" + integrity sha512-czlJHbaU9RdaoJNV35NnzRjie/+AogErv68O0DvgwnFFSO3J8pF5xLZYkv5ZG4hyW7Vtx+NwRRTM60DRzxDGww== dependencies: "@floating-ui/dom" "^1.5.1" "@lit/reactive-element" "^1.0.0" From aa47e2d0a74b427101c7b727b4ae5082995b4a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Thu, 25 Apr 2024 17:34:31 +0200 Subject: [PATCH 076/103] updated pkgs --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 81e9ed974..fd354e08e 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@galacticcouncil/math-staking": "^0.2.0", "@galacticcouncil/math-xyk": "^0.2.0", "@galacticcouncil/sdk": "^2.2.3", - "@galacticcouncil/ui": "^3.1.13", + "@galacticcouncil/ui": "^3.1.14", "@galacticcouncil/xcm-cfg": "^1.11.6", "@galacticcouncil/xcm-sdk": "^2.4.0", "@hookform/resolvers": "^3.3.4", diff --git a/yarn.lock b/yarn.lock index 4688bdbef..db0ffbbe6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3076,10 +3076,10 @@ bignumber.js "^9.1.0" lodash.clonedeep "^4.5.0" -"@galacticcouncil/ui@^3.1.13": - version "3.1.13" - resolved "https://registry.yarnpkg.com/@galacticcouncil/ui/-/ui-3.1.13.tgz#6a59a591de4dce05a9e094b226784b2072fcc590" - integrity sha512-czlJHbaU9RdaoJNV35NnzRjie/+AogErv68O0DvgwnFFSO3J8pF5xLZYkv5ZG4hyW7Vtx+NwRRTM60DRzxDGww== +"@galacticcouncil/ui@^3.1.14": + version "3.1.14" + resolved "https://registry.yarnpkg.com/@galacticcouncil/ui/-/ui-3.1.14.tgz#09bf5cb8abb47d16fd7e4a75b7221e4c0e08c249" + integrity sha512-D580RMrfsLJO+68SewCSacDOUfVoM8BfyElw/bLqlcD46fUMhETghpLgIfuRIOEYyK7Y5s0qIBJOxaKdBKRwGw== dependencies: "@floating-ui/dom" "^1.5.1" "@lit/reactive-element" "^1.0.0" From 0f9db28927c67a5b493cb34ede74317fe887f519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Thu, 25 Apr 2024 18:39:29 +0200 Subject: [PATCH 077/103] blacklist pendulum --- src/sections/xcm/XcmPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sections/xcm/XcmPage.tsx b/src/sections/xcm/XcmPage.tsx index 0dbb88163..f84f4e537 100644 --- a/src/sections/xcm/XcmPage.tsx +++ b/src/sections/xcm/XcmPage.tsx @@ -148,6 +148,7 @@ export function XcmPage() { onXcmNew={handleSubmit} onWalletChange={handleWalletChange} ss58Prefix={ss58Prefix} + blacklist="pendulum" /> From 6e067fb3a4e4cfaf54125b75da27e58e28c9f522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Thu, 25 Apr 2024 18:47:50 +0200 Subject: [PATCH 078/103] Update pkgs --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index fd354e08e..f4fad9d19 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@galacticcouncil/math-xyk": "^0.2.0", "@galacticcouncil/sdk": "^2.2.3", "@galacticcouncil/ui": "^3.1.14", - "@galacticcouncil/xcm-cfg": "^1.11.6", + "@galacticcouncil/xcm-cfg": "^1.11.7", "@galacticcouncil/xcm-sdk": "^2.4.0", "@hookform/resolvers": "^3.3.4", "@lit-labs/react": "^1.1.0", diff --git a/yarn.lock b/yarn.lock index db0ffbbe6..d97576dd1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3087,10 +3087,10 @@ lit "^2.5.0" ts-debounce "^4.0.0" -"@galacticcouncil/xcm-cfg@^1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@galacticcouncil/xcm-cfg/-/xcm-cfg-1.11.6.tgz#ed5a0caeeb92d2bfcb331a00cfe91edf3b13d895" - integrity sha512-xnH166yQIVNX0xiXq0hekz+lHxFcZxsVH3mOHvg0uJ5RE80b3FkQDOV5Xb1YyqtJrrcldhzAG1Z8DSMw/Ef1dw== +"@galacticcouncil/xcm-cfg@^1.11.7": + version "1.11.7" + resolved "https://registry.yarnpkg.com/@galacticcouncil/xcm-cfg/-/xcm-cfg-1.11.7.tgz#46cb3d2064879a9f67696187571373232199935c" + integrity sha512-2s40nBxMCY6Z9Iw31e+rJk50bnTKC7zpd/TfrT8AKtw0SHfqhf1mpxGWyOwvafk6Suvw1sAgQd353Uw3KMi04g== "@galacticcouncil/xcm-sdk@^2.4.0": version "2.4.0" From 3773d7220e5e2c0204b549bb12868ad5e691df04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Fri, 26 Apr 2024 13:08:43 +0200 Subject: [PATCH 079/103] hide external token from asset selector, if its not in LS --- src/sections/assets/AssetsModal.tsx | 4 +++- src/sections/trade/sections/otc/modals/FillOrder.tsx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sections/assets/AssetsModal.tsx b/src/sections/assets/AssetsModal.tsx index 64a56dddb..29f6a0d44 100644 --- a/src/sections/assets/AssetsModal.tsx +++ b/src/sections/assets/AssetsModal.tsx @@ -85,7 +85,9 @@ export const AssetsModalContent = ({ (accountAsset): accountAsset is { balance: TBalance; asset: TToken } => accountAsset.asset.isToken || accountAsset.asset.isStableSwap || - (withExternal ? accountAsset.asset.isExternal : false) || + (withExternal + ? accountAsset.asset.isExternal && !!accountAsset.asset.name + : false) || (withShareTokens ? accountAsset.asset.isShareToken : false), ) diff --git a/src/sections/trade/sections/otc/modals/FillOrder.tsx b/src/sections/trade/sections/otc/modals/FillOrder.tsx index 998082eb5..a662f2a53 100644 --- a/src/sections/trade/sections/otc/modals/FillOrder.tsx +++ b/src/sections/trade/sections/otc/modals/FillOrder.tsx @@ -99,7 +99,7 @@ export const FillOrder = ({ } const isDisabled = - assetInBalance.data?.balance?.lte( + assetInBalance.data?.balance?.lt( accepting.amount.multipliedBy(BN_10.pow(assetInMeta.decimals)), ) ?? false From 0e6ff89dcfbfc9ee0326b91d1e5f32198fe93744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Mon, 29 Apr 2024 17:58:56 +0200 Subject: [PATCH 080/103] wip --- package.json | 3 +- .../transaction/ReviewTransactionForm.tsx | 30 ++-- .../paymentAsset/WalletPaymentAsset.tsx | 4 +- .../wallets/MetaMask/MetaMaskSigner.ts | 69 ++++++++ yarn.lock | 167 +++++++++++++++++- 5 files changed, 251 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index f4fad9d19..f85c2338f 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@galacticcouncil/xcm-sdk": "^2.4.0", "@hookform/resolvers": "^3.3.4", "@lit-labs/react": "^1.1.0", + "@metamask/eth-sig-util": "^7.0.1", "@polkadot/api": "10.9.1", "@polkadot/apps-config": "^0.132.1", "@polkadot/extension-inject": "^0.44.5", @@ -77,7 +78,7 @@ "color": "^4.2.3", "comlink": "^4.3.1", "date-fns": "^2.29.1", - "ethers": "^5.7.0", + "ethers": "5.7.0", "ethers-decode-error": "^1.0.0", "framer-motion": "^10.16.4", "graphql": "^16.6.0", diff --git a/src/sections/transaction/ReviewTransactionForm.tsx b/src/sections/transaction/ReviewTransactionForm.tsx index 373d810d8..45649b6f0 100644 --- a/src/sections/transaction/ReviewTransactionForm.tsx +++ b/src/sections/transaction/ReviewTransactionForm.tsx @@ -95,8 +95,14 @@ export const ReviewTransactionForm: FC = (props) => { if (!wallet.signer) throw new Error("Missing signer") if (wallet?.signer instanceof MetaMaskSigner) { - const evmTx = await wallet.signer.sendDispatch(tx.method.toHex()) - return props.onEvmSigned({ evmTx, tx }) + //const evmTx = await wallet.signer.sendDispatch(tx.method.toHex()) + const permit = await wallet.signer.sendPermitDispatch( + tx.method.toHex(), + ) + + console.log({ permit }) + + //return props.onEvmSigned({ evmTx, tx }) } const signature = await tx.signAsync(address, { @@ -125,17 +131,15 @@ export const ReviewTransactionForm: FC = (props) => { : acceptedFeePaymentAssets.length > 1 const isEditPaymentBalance = !isEnoughPaymentBalance && hasMultipleFeeAssets - const isEvmFeePaymentAssetInvalid = isEvmAccount(account?.address) + /* const isEvmFeePaymentAssetInvalid = isEvmAccount(account?.address) ? feePaymentMeta?.id !== NATIVE_EVM_ASSET_ID - : false + : false */ if (isOpenEditFeePaymentAssetModal) return editFeePaymentAssetModal const onConfirmClick = () => shouldOpenPolkaJSUrl ? window.open(polkadotJSUrl, "_blank") - : isEvmFeePaymentAssetInvalid - ? openEditFeePaymentAssetModal() : isEnoughPaymentBalance ? signTx.mutate() : hasMultipleFeeAssets @@ -148,7 +152,7 @@ export const ReviewTransactionForm: FC = (props) => { btnText = t( "liquidity.reviewTransaction.modal.confirmButton.openPolkadotJS", ) - } else if (isEditPaymentBalance || isEvmFeePaymentAssetInvalid) { + } else if (isEditPaymentBalance) { btnText = t( "liquidity.reviewTransaction.modal.confirmButton.notEnoughBalance", ) @@ -181,9 +185,7 @@ export const ReviewTransactionForm: FC = (props) => { = (props) => { } onClick={onConfirmClick} /> - {!shouldOpenPolkaJSUrl && isEvmFeePaymentAssetInvalid && ( - - {t( - "liquidity.reviewTransaction.modal.confirmButton.invalidEvmPaymentAsset.msg", - { symbol: NATIVE_EVM_ASSET_SYMBOL }, - )} - - )} {!isEnoughPaymentBalance && !transactionValues.isLoading && ( {t( diff --git a/src/sections/wallet/assets/paymentAsset/WalletPaymentAsset.tsx b/src/sections/wallet/assets/paymentAsset/WalletPaymentAsset.tsx index 3ba8961f0..aa7a7a9c3 100644 --- a/src/sections/wallet/assets/paymentAsset/WalletPaymentAsset.tsx +++ b/src/sections/wallet/assets/paymentAsset/WalletPaymentAsset.tsx @@ -34,12 +34,12 @@ export const WalletPaymentAsset = () => { const isFeePaymentAssetEditable = acceptedFeePaymentAssetsIds.length > 1 - const isEvm = isEvmAccount(account?.address) + /* const isEvm = isEvmAccount(account?.address) if (isEvm) { return null } - + */ return (
diff --git a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts index 545720b3f..8d53b6443 100644 --- a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts +++ b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts @@ -6,6 +6,10 @@ import { import { evmChains } from "@galacticcouncil/xcm-sdk" import { DISPATCH_ADDRESS } from "utils/evm" import { MetaMaskLikeProvider, requestNetworkSwitch } from "utils/metamask" +import { SignatureLike } from "@ethersproject/bytes" +import { signTypedData, SignTypedDataVersion } from "@metamask/eth-sig-util" +import { ethers } from "ethers" +import { Buffer } from "buffer" export class MetaMaskSigner { address: string @@ -41,6 +45,71 @@ export class MetaMaskSigner { }) } + extractRSV = ( + signatureHex: string, + ): { + r: string + s: string + v: number + } => { + const signature = Buffer.from(signatureHex.slice(2), "hex") + const r = signature.slice(0, 32).toString("hex") + const s = signature.slice(32, 64).toString("hex") + const v = signature[64] + return { r, s, v } + } + + sendPermitDispatch = async (data: string): Promise => { + if (this.provider && this.address) { + const createPermitMessageData = () => { + const message = { + from: this.address, + to: DISPATCH_ADDRESS, + data: data, + } + + const typedData = { + types: { + CallPermit: [ + { name: "from", type: "address" }, + { name: "to", type: "address" }, + { name: "data", type: "bytes" }, + ], + }, + primaryType: "CallPermit", + domain: { + name: "Call Permit Precompile", + version: "1", + chainId: 222222, + verifyingContract: "0x000000000000000000000000000000000000080a", + }, + message: message, + } + + return { + typedData, + message, + } + } + + const messageData = createPermitMessageData() + + const signature = await this.signer._signTypedData( + messageData.typedData.domain, + messageData.typedData.types, + messageData.message, + ) + + console.log(signature, this.extractRSV(signature)) + + //const ethersSignature = Signature.from(signature) + + return signature + } + + throw new Error("Error signing transaction. Provider not found") + } + sendTransaction = async ( transaction: TransactionRequest & { chain?: string }, ) => { diff --git a/yarn.lock b/yarn.lock index d97576dd1..555cda974 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2600,6 +2600,38 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484" integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ== +"@ethereumjs/common@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-3.2.0.tgz#b71df25845caf5456449163012074a55f048e0a0" + integrity sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA== + dependencies: + "@ethereumjs/util" "^8.1.0" + crc-32 "^1.2.0" + +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + +"@ethereumjs/tx@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-4.2.0.tgz#5988ae15daf5a3b3c815493bc6b495e76009e853" + integrity sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw== + dependencies: + "@ethereumjs/common" "^3.2.0" + "@ethereumjs/rlp" "^4.0.1" + "@ethereumjs/util" "^8.1.0" + ethereum-cryptography "^2.0.0" + +"@ethereumjs/util@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" + integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" + "@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" @@ -3371,6 +3403,41 @@ "@types/mdx" "^2.0.0" "@types/react" ">=16" +"@metamask/abi-utils@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@metamask/abi-utils/-/abi-utils-2.0.2.tgz#ad394e9cb8a95ac177cad942daadd88a246c0de8" + integrity sha512-B/A1dY/w4F/t6cDHUscklO6ovb/ztFsrsTXFd8QlqSByk/vyy+QbPE3VVpmmyI/7RX+PA1AJcvBdzCIz+r9dVQ== + dependencies: + "@metamask/utils" "^8.0.0" + superstruct "^1.0.3" + +"@metamask/eth-sig-util@^7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-7.0.1.tgz#ad3227d6120f15f9293478de7dd9685a5c329586" + integrity sha512-59GSrMyFH2fPfu7nKeIQdZ150zxXNNhAQIUaFRUW+MGtVA4w/ONbiQobcRBLi+jQProfIyss51G8pfLPcQ0ylg== + dependencies: + "@ethereumjs/util" "^8.1.0" + "@metamask/abi-utils" "^2.0.2" + "@metamask/utils" "^8.1.0" + ethereum-cryptography "^2.1.2" + tweetnacl "^1.0.3" + tweetnacl-util "^0.15.1" + +"@metamask/utils@^8.0.0", "@metamask/utils@^8.1.0": + version "8.4.0" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-8.4.0.tgz#f44812c96467a4e1b70b2edff6ee89a9caa4e354" + integrity sha512-dbIc3C7alOe0agCuBHM1h71UaEaEqOk2W8rAtEn8QGz4haH2Qq7MoK6i7v2guzvkJVVh79c+QCzIqphC3KvrJg== + dependencies: + "@ethereumjs/tx" "^4.2.0" + "@noble/hashes" "^1.3.1" + "@scure/base" "^1.1.3" + "@types/debug" "^4.1.7" + debug "^4.3.4" + pony-cause "^2.1.10" + semver "^7.5.4" + superstruct "^1.0.3" + uuid "^9.0.1" + "@metaverse-network-sdk/type-definitions@0.0.1-16": version "0.0.1-16" resolved "https://registry.yarnpkg.com/@metaverse-network-sdk/type-definitions/-/type-definitions-0.0.1-16.tgz#43f85125064cbd199f0b33e47990debd15e7fdbb" @@ -3512,6 +3579,13 @@ dependencies: "@noble/hashes" "1.3.2" +"@noble/curves@1.3.0", "@noble/curves@~1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" + integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== + dependencies: + "@noble/hashes" "1.3.3" + "@noble/hashes@1.3.1": version "1.3.1" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" @@ -3522,11 +3596,16 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== -"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2": +"@noble/hashes@1.3.3", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== +"@noble/hashes@^1.3.1": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -4666,6 +4745,11 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== +"@scure/base@^1.1.3", "@scure/base@~1.1.4": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" + integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== + "@scure/base@~1.1.0", "@scure/base@~1.1.2": version "1.1.6" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" @@ -4680,6 +4764,15 @@ "@noble/hashes" "~1.3.2" "@scure/base" "~1.1.2" +"@scure/bip32@1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.3.tgz#a9624991dc8767087c57999a5d79488f48eae6c8" + integrity sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ== + dependencies: + "@noble/curves" "~1.3.0" + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.4" + "@scure/bip39@1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a" @@ -4688,6 +4781,14 @@ "@noble/hashes" "~1.3.0" "@scure/base" "~1.1.0" +"@scure/bip39@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.2.tgz#f3426813f4ced11a47489cbcf7294aa963966527" + integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA== + dependencies: + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.4" + "@sinclair/typebox@^0.25.16": version "0.25.24" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" @@ -6403,6 +6504,13 @@ resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.0.tgz#e2505f1c21ec08bda8915238e397fb71d2fc54ce" integrity sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g== +"@types/debug@^4.1.7": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" + integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== + dependencies: + "@types/ms" "*" + "@types/detect-port@^1.3.0": version "1.3.3" resolved "https://registry.yarnpkg.com/@types/detect-port/-/detect-port-1.3.3.tgz#124c5d4c283f48a21f80826bcf39433b3e64aa81" @@ -6573,6 +6681,11 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== +"@types/ms@*": + version "0.7.34" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" + integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== + "@types/node-fetch@^2.6.4": version "2.6.4" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.4.tgz#1bc3a26de814f6bf466b25aeb1473fa1afe6a660" @@ -8243,6 +8356,11 @@ cosmiconfig@^8.1.3, cosmiconfig@^8.2.0: parse-json "^5.0.0" path-type "^4.0.0" +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -9312,6 +9430,16 @@ ethereum-blockies-base64@^1.0.2: dependencies: pnglib "0.0.1" +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz#1352270ed3b339fe25af5ceeadcf1b9c8e30768a" + integrity sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA== + dependencies: + "@noble/curves" "1.3.0" + "@noble/hashes" "1.3.3" + "@scure/bip32" "1.3.3" + "@scure/bip39" "1.2.2" + ethers-decode-error@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ethers-decode-error/-/ethers-decode-error-1.0.0.tgz#85f044a74173914a1d4b5f9bac6a132c9bfd51af" @@ -11335,6 +11463,11 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== +micro-ftch@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" + integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== + micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -12199,6 +12332,11 @@ pontem-types-bundle@1.0.15: "@polkadot/types" "^6.0.5" typescript "^4.4.3" +pony-cause@^2.1.10: + version "2.1.10" + resolved "https://registry.yarnpkg.com/pony-cause/-/pony-cause-2.1.10.tgz#828457ad6f13be401a075dbf14107a9057945174" + integrity sha512-3IKLNXclQgkU++2fSi93sQ6BznFuxSLB11HdvZQ6JW/spahf/P1pAHBQEahr20rs0htZW0UDkM1HmA+nZkXKsw== + postcss-loader@^7.2.4: version "7.3.3" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.3.3.tgz#6da03e71a918ef49df1bb4be4c80401df8e249dd" @@ -13172,6 +13310,13 @@ semver@^7.3.8: dependencies: lru-cache "^6.0.0" +semver@^7.5.4: + version "7.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + semver@~7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" @@ -13684,6 +13829,11 @@ stylis@^4.3.0: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.0.tgz#abe305a669fc3d8777e10eefcfc73ad861c5588c" integrity sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ== +superstruct@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.4.tgz#0adb99a7578bd2f1c526220da6571b2d485d91ca" + integrity sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ== + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -13982,6 +14132,16 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" +tweetnacl-util@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" + integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== + +tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -14255,6 +14415,11 @@ uuid@^9.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" From c31637eb08203ffeeb7160ef2daeb0ab58ea10fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Tue, 30 Apr 2024 13:34:21 +0200 Subject: [PATCH 081/103] wip --- .../transaction/ReviewTransactionForm.tsx | 26 ++- .../wallets/MetaMask/MetaMaskSigner.ts | 157 +++++++++++++----- src/sections/web3-connect/wallets/index.ts | 7 +- src/utils/evm.ts | 2 + 4 files changed, 147 insertions(+), 45 deletions(-) diff --git a/src/sections/transaction/ReviewTransactionForm.tsx b/src/sections/transaction/ReviewTransactionForm.tsx index 45649b6f0..8a5af713e 100644 --- a/src/sections/transaction/ReviewTransactionForm.tsx +++ b/src/sections/transaction/ReviewTransactionForm.tsx @@ -21,11 +21,16 @@ import { HYDRADX_CHAIN_KEY } from "sections/xcm/XcmPage.utils" import { useReferralCodesStore } from "sections/referrals/store/useReferralCodesStore" import BN from "bignumber.js" import { + DISPATCH_ADDRESS, NATIVE_EVM_ASSET_ID, NATIVE_EVM_ASSET_SYMBOL, isEvmAccount, } from "utils/evm" -import { isSetCurrencyExtrinsic } from "sections/transaction/ReviewTransaction.utils" +import { + getTransactionJSON, + isSetCurrencyExtrinsic, +} from "sections/transaction/ReviewTransaction.utils" +import { useRpcProvider } from "providers/rpcProvider" type TxProps = Omit & { tx: SubmittableExtrinsic<"promise"> @@ -46,6 +51,8 @@ export const ReviewTransactionForm: FC = (props) => { const { t } = useTranslation() const { account } = useAccount() const { setReferralCode } = useReferralCodesStore() + const { api } = useRpcProvider() + const { createTransaction } = useStore() const polkadotJSUrl = usePolkadotJSTxUrl(props.tx) @@ -99,9 +106,24 @@ export const ReviewTransactionForm: FC = (props) => { const permit = await wallet.signer.sendPermitDispatch( tx.method.toHex(), ) - console.log({ permit }) + const res = await api.tx.multiTransactionPayment + .dispatchPermit( + permit.message.from, + permit.message.to, + permit.message.value, + permit.message.data, + permit.message.gaslimit, + permit.message.deadline, + permit.signature.v, + permit.signature.r, + permit.signature.s, + ) + .send() + + console.log({ res }) + //return props.onEvmSigned({ evmTx, tx }) } diff --git a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts index 8d53b6443..b07e3e4f9 100644 --- a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts +++ b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts @@ -4,12 +4,24 @@ import { Web3Provider, } from "@ethersproject/providers" import { evmChains } from "@galacticcouncil/xcm-sdk" -import { DISPATCH_ADDRESS } from "utils/evm" +import { Contract, Signature } from "ethers" +import { splitSignature } from "ethers/lib/utils" +import { + CALL_PERMIT_ABI, + CALL_PERMIT_ADDRESS, + DISPATCH_ADDRESS, +} from "utils/evm" import { MetaMaskLikeProvider, requestNetworkSwitch } from "utils/metamask" -import { SignatureLike } from "@ethersproject/bytes" -import { signTypedData, SignTypedDataVersion } from "@metamask/eth-sig-util" -import { ethers } from "ethers" -import { Buffer } from "buffer" + +type PermitMessage = { + from: string + to: string + value: number + data: string + gaslimit: number + nonce: number + deadline: number +} export class MetaMaskSigner { address: string @@ -45,46 +57,97 @@ export class MetaMaskSigner { }) } - extractRSV = ( - signatureHex: string, - ): { - r: string - s: string - v: number - } => { - const signature = Buffer.from(signatureHex.slice(2), "hex") - const r = signature.slice(0, 32).toString("hex") - const s = signature.slice(32, 64).toString("hex") - const v = signature[64] - return { r, s, v } + getPermitNonce = async () => { + const callPermit = new Contract( + CALL_PERMIT_ADDRESS, + CALL_PERMIT_ABI, + this.signer.provider, + ) + + return callPermit.nonces(this.address) } - sendPermitDispatch = async (data: string): Promise => { + sendPermitDispatch = async ( + data: string, + ): Promise<{ signature: Signature; message: PermitMessage }> => { if (this.provider && this.address) { + const nonce = await this.getPermitNonce() + const tx = { + from: this.address, + to: DISPATCH_ADDRESS, + data, + } + + const [gas] = await this.getGasValues(tx) const createPermitMessageData = () => { - const message = { - from: this.address, - to: DISPATCH_ADDRESS, - data: data, + const message: PermitMessage = { + ...tx, + value: 0, + gaslimit: gas.mul(11).div(10).toNumber(), + nonce: nonce.toNumber(), + deadline: Math.floor(Date.now() / 1000 + 3600), } - const typedData = { + const typedData = JSON.stringify({ types: { + EIP712Domain: [ + { + name: "name", + type: "string", + }, + { + name: "version", + type: "string", + }, + { + name: "chainId", + type: "uint256", + }, + { + name: "verifyingContract", + type: "address", + }, + ], CallPermit: [ - { name: "from", type: "address" }, - { name: "to", type: "address" }, - { name: "data", type: "bytes" }, + { + name: "from", + type: "address", + }, + { + name: "to", + type: "address", + }, + { + name: "value", + type: "uint256", + }, + { + name: "data", + type: "bytes", + }, + { + name: "gaslimit", + type: "uint64", + }, + { + name: "nonce", + type: "uint256", + }, + { + name: "deadline", + type: "uint256", + }, ], }, primaryType: "CallPermit", domain: { name: "Call Permit Precompile", version: "1", - chainId: 222222, - verifyingContract: "0x000000000000000000000000000000000000080a", + chainId: parseInt(import.meta.env.VITE_EVM_CHAIN_ID), + verifyingContract: CALL_PERMIT_ADDRESS, }, message: message, - } + }) return { typedData, @@ -92,19 +155,39 @@ export class MetaMaskSigner { } } - const messageData = createPermitMessageData() + const { message, typedData } = createPermitMessageData() - const signature = await this.signer._signTypedData( - messageData.typedData.domain, - messageData.typedData.types, - messageData.message, - ) + const method = "eth_signTypedData_v4" + const params = [this.address, typedData] - console.log(signature, this.extractRSV(signature)) + /* const signature = await this.signer._signTypedData( + typedData.domain, + typedData.types, + message, + ) + */ + //const signature: SignatureLike = await provider.send( //const ethersSignature = Signature.from(signature) - return signature + return new Promise((resolve, reject) => { + this.provider.sendAsync?.( + { + method, + params, + }, + (err, result) => { + if (err) { + return reject(err) + } + + return resolve({ + message, + signature: splitSignature(result.result), + }) + }, + ) + }) } throw new Error("Error signing transaction. Provider not found") diff --git a/src/sections/web3-connect/wallets/index.ts b/src/sections/web3-connect/wallets/index.ts index 3e6036c38..5cbc0adb4 100644 --- a/src/sections/web3-connect/wallets/index.ts +++ b/src/sections/web3-connect/wallets/index.ts @@ -1,9 +1,4 @@ -import { - SubscriptionFn, - Wallet, - WalletAccount, - getWallets, -} from "@talismn/connect-wallets" +import { SubscriptionFn, Wallet, getWallets } from "@talismn/connect-wallets" import { ExternalWallet } from "./ExternalWallet" import { MetaMask } from "./MetaMask" diff --git a/src/utils/evm.ts b/src/utils/evm.ts index 6a682f650..8fef9ddce 100644 --- a/src/utils/evm.ts +++ b/src/utils/evm.ts @@ -16,6 +16,8 @@ export const NATIVE_EVM_ASSET_ID = import.meta.env .VITE_EVM_NATIVE_ASSET_ID as string export const DISPATCH_ADDRESS = "0x0000000000000000000000000000000000000401" +export const CALL_PERMIT_ADDRESS = "0x0000000000000000000000000000000000000010" +export const CALL_PERMIT_ABI = `[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"gaslimit","type":"uint64"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"dispatch","outputs":[{"internalType":"bytes","name":"output","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` export function isEvmAccount(address?: string) { if (!address) return false From a140eb3c868bd3fa0d32158ffc2860babdc78083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Tue, 30 Apr 2024 15:44:42 +0200 Subject: [PATCH 082/103] Enable payment asset changing for EVM, cleanup --- src/api/payments.ts | 12 +--- .../transaction/ReviewTransactionForm.tsx | 64 ++++++++----------- .../ReviewTransactionForm.utils.tsx | 5 ++ .../actions/WalletAssetsTableActions.tsx | 5 +- .../actions/WalletAssetsTableActionsMob.tsx | 29 ++++----- .../wallets/MetaMask/MetaMaskSigner.ts | 11 +--- 6 files changed, 48 insertions(+), 78 deletions(-) diff --git a/src/api/payments.ts b/src/api/payments.ts index 89085f846..bfd4589d3 100644 --- a/src/api/payments.ts +++ b/src/api/payments.ts @@ -12,7 +12,6 @@ import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { useAcountAssets } from "api/assetDetails" import { useMemo } from "react" import { uniqBy } from "utils/rx" -import { NATIVE_EVM_ASSET_ID, isEvmAccount } from "utils/evm" export const getAcceptedCurrency = (api: ApiPromise) => async () => { const dataRaw = @@ -103,24 +102,15 @@ export const useAccountCurrency = (address: Maybe) => { } export const useAccountFeePaymentAssets = () => { - const { assets } = useRpcProvider() const { account } = useAccount() const accountAssets = useAcountAssets(account?.address) const accountFeePaymentAsset = useAccountCurrency(account?.address) const feePaymentAssetId = accountFeePaymentAsset.data const allowedFeePaymentAssetsIds = useMemo(() => { - if (isEvmAccount(account?.address)) { - const evmNativeAssetId = assets.getAsset(NATIVE_EVM_ASSET_ID).id - return uniqBy( - identity, - [evmNativeAssetId, feePaymentAssetId].filter(isNotNil), - ) - } - const assetIds = accountAssets.map((accountAsset) => accountAsset.asset.id) return uniqBy(identity, [...assetIds, feePaymentAssetId].filter(isNotNil)) - }, [assets, account?.address, accountAssets, feePaymentAssetId]) + }, [accountAssets, feePaymentAssetId]) const acceptedFeePaymentAssets = useAcceptedCurrencies( allowedFeePaymentAssetsIds, diff --git a/src/sections/transaction/ReviewTransactionForm.tsx b/src/sections/transaction/ReviewTransactionForm.tsx index 8a5af713e..e8ecb416a 100644 --- a/src/sections/transaction/ReviewTransactionForm.tsx +++ b/src/sections/transaction/ReviewTransactionForm.tsx @@ -20,16 +20,8 @@ import { ReviewTransactionSummary } from "sections/transaction/ReviewTransaction import { HYDRADX_CHAIN_KEY } from "sections/xcm/XcmPage.utils" import { useReferralCodesStore } from "sections/referrals/store/useReferralCodesStore" import BN from "bignumber.js" -import { - DISPATCH_ADDRESS, - NATIVE_EVM_ASSET_ID, - NATIVE_EVM_ASSET_SYMBOL, - isEvmAccount, -} from "utils/evm" -import { - getTransactionJSON, - isSetCurrencyExtrinsic, -} from "sections/transaction/ReviewTransaction.utils" +import { NATIVE_EVM_ASSET_ID, isEvmAccount } from "utils/evm" +import { isSetCurrencyExtrinsic } from "sections/transaction/ReviewTransaction.utils" import { useRpcProvider } from "providers/rpcProvider" type TxProps = Omit & { @@ -52,7 +44,6 @@ export const ReviewTransactionForm: FC = (props) => { const { account } = useAccount() const { setReferralCode } = useReferralCodesStore() const { api } = useRpcProvider() - const { createTransaction } = useStore() const polkadotJSUrl = usePolkadotJSTxUrl(props.tx) @@ -77,6 +68,7 @@ export const ReviewTransactionForm: FC = (props) => { acceptedFeePaymentAssets, isEnoughPaymentBalance, feePaymentMeta, + originalFeePaymentMeta, isLinkedAccount, storedReferralCode, tx, @@ -102,29 +94,33 @@ export const ReviewTransactionForm: FC = (props) => { if (!wallet.signer) throw new Error("Missing signer") if (wallet?.signer instanceof MetaMaskSigner) { - //const evmTx = await wallet.signer.sendDispatch(tx.method.toHex()) - const permit = await wallet.signer.sendPermitDispatch( - tx.method.toHex(), - ) - console.log({ permit }) - - const res = await api.tx.multiTransactionPayment - .dispatchPermit( - permit.message.from, - permit.message.to, - permit.message.value, - permit.message.data, - permit.message.gaslimit, - permit.message.deadline, - permit.signature.v, - permit.signature.r, - permit.signature.s, + const shouldUsePermit = + originalFeePaymentMeta?.id !== NATIVE_EVM_ASSET_ID + if (shouldUsePermit) { + const permit = await wallet.signer.sendPermitDispatch( + tx.method.toHex(), ) - .send() - console.log({ res }) - - //return props.onEvmSigned({ evmTx, tx }) + const res = await api.tx.multiTransactionPayment + .dispatchPermit( + permit.message.from, + permit.message.to, + permit.message.value, + permit.message.data, + permit.message.gaslimit, + permit.message.deadline, + permit.signature.v, + permit.signature.r, + permit.signature.s, + ) + .send() + // @TODO handle permit result + console.log({ res }) + return + } + + const evmTx = await wallet.signer.sendDispatch(tx.method.toHex()) + return props.onEvmSigned({ evmTx, tx }) } const signature = await tx.signAsync(address, { @@ -153,10 +149,6 @@ export const ReviewTransactionForm: FC = (props) => { : acceptedFeePaymentAssets.length > 1 const isEditPaymentBalance = !isEnoughPaymentBalance && hasMultipleFeeAssets - /* const isEvmFeePaymentAssetInvalid = isEvmAccount(account?.address) - ? feePaymentMeta?.id !== NATIVE_EVM_ASSET_ID - : false */ - if (isOpenEditFeePaymentAssetModal) return editFeePaymentAssetModal const onConfirmClick = () => diff --git a/src/sections/transaction/ReviewTransactionForm.utils.tsx b/src/sections/transaction/ReviewTransactionForm.utils.tsx index d92c53d1c..69b3be2ee 100644 --- a/src/sections/transaction/ReviewTransactionForm.utils.tsx +++ b/src/sections/transaction/ReviewTransactionForm.utils.tsx @@ -90,6 +90,10 @@ export const useTransactionValues = ({ ? assets.getAsset(accountFeePaymentId) : undefined + const originalFeePaymentMeta = feePaymentAssetId + ? assets.getAsset(feePaymentAssetId) + : undefined + const spotPrice = useSpotPrice(assets.native.id, accountFeePaymentId) const feeAssetBalance = useTokenBalance(accountFeePaymentId, account?.address) @@ -131,6 +135,7 @@ export const useTransactionValues = ({ isEnoughPaymentBalance: false, displayFeePaymentValue: BN_NAN, feePaymentMeta, + originalFeePaymentMeta, acceptedFeePaymentAssets: [], era, nonce: nonce.data, diff --git a/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx b/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx index 4e1a349d1..a16b0db9d 100644 --- a/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx +++ b/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx @@ -50,9 +50,6 @@ export const WalletAssetsTableActions = (props: Props) => { tradability: { inTradeRouter, canBuy }, } = props.asset - const enablePaymentFee = - couldBeSetAsPaymentFee && !isEvmAccount(account?.address) - const couldWatchMetaMaskAsset = isMetaMask(window?.ethereum) && isEvmAccount(account?.address) && @@ -129,7 +126,7 @@ export const WalletAssetsTableActions = (props: Props) => { ] const actionItems = [ - enablePaymentFee + couldBeSetAsPaymentFee ? { key: "setAsFeePayment", icon: , diff --git a/src/sections/wallet/assets/table/actions/WalletAssetsTableActionsMob.tsx b/src/sections/wallet/assets/table/actions/WalletAssetsTableActionsMob.tsx index 44c684c49..ad54dcedb 100644 --- a/src/sections/wallet/assets/table/actions/WalletAssetsTableActionsMob.tsx +++ b/src/sections/wallet/assets/table/actions/WalletAssetsTableActionsMob.tsx @@ -22,7 +22,6 @@ import { } from "sections/wallet/assets/table/data/WalletAssetsTableData.utils" import Skeleton from "react-loading-skeleton" import { AddTokenAction } from "./WalletAssetsTableActions" -import { isEvmAccount } from "utils/evm" type Props = { row?: AssetsTableData @@ -47,8 +46,6 @@ export const WalletAssetsTableActionsMob = ({ const isNativeAsset = row.id === NATIVE_ASSET_ID - const isEvm = isEvmAccount(account?.address) - return (
@@ -238,20 +235,18 @@ export const WalletAssetsTableActionsMob = ({ - {!isEvm && ( - - )} +
)} diff --git a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts index b07e3e4f9..cbcc41a39 100644 --- a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts +++ b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts @@ -79,6 +79,7 @@ export class MetaMaskSigner { } const [gas] = await this.getGasValues(tx) + const createPermitMessageData = () => { const message: PermitMessage = { ...tx, @@ -160,16 +161,6 @@ export class MetaMaskSigner { const method = "eth_signTypedData_v4" const params = [this.address, typedData] - /* const signature = await this.signer._signTypedData( - typedData.domain, - typedData.types, - message, - ) - */ - //const signature: SignatureLike = await provider.send( - - //const ethersSignature = Signature.from(signature) - return new Promise((resolve, reject) => { this.provider.sendAsync?.( { From fd239ef4362b033d8d8b25588664fb39fa96a595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Tue, 30 Apr 2024 15:48:09 +0200 Subject: [PATCH 083/103] update package.json --- package.json | 1 - yarn.lock | 231 ++++++++++++--------------------------------------- 2 files changed, 55 insertions(+), 177 deletions(-) diff --git a/package.json b/package.json index f85c2338f..62dd471ed 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "@galacticcouncil/xcm-sdk": "^2.4.0", "@hookform/resolvers": "^3.3.4", "@lit-labs/react": "^1.1.0", - "@metamask/eth-sig-util": "^7.0.1", "@polkadot/api": "10.9.1", "@polkadot/apps-config": "^0.132.1", "@polkadot/extension-inject": "^0.44.5", diff --git a/yarn.lock b/yarn.lock index 555cda974..2e50d00af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2600,38 +2600,6 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484" integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ== -"@ethereumjs/common@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-3.2.0.tgz#b71df25845caf5456449163012074a55f048e0a0" - integrity sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA== - dependencies: - "@ethereumjs/util" "^8.1.0" - crc-32 "^1.2.0" - -"@ethereumjs/rlp@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" - integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== - -"@ethereumjs/tx@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-4.2.0.tgz#5988ae15daf5a3b3c815493bc6b495e76009e853" - integrity sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw== - dependencies: - "@ethereumjs/common" "^3.2.0" - "@ethereumjs/rlp" "^4.0.1" - "@ethereumjs/util" "^8.1.0" - ethereum-cryptography "^2.0.0" - -"@ethereumjs/util@^8.1.0": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" - integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== - dependencies: - "@ethereumjs/rlp" "^4.0.1" - ethereum-cryptography "^2.0.0" - micro-ftch "^0.3.1" - "@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" @@ -2801,7 +2769,14 @@ resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== -"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": +"@ethersproject/networks@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.0.tgz#df72a392f1a63a57f87210515695a31a245845ad" + integrity sha512-MG6oHSQHd4ebvJrleEQQ4HhVu8Ichr0RDYEfHzsVAVjHNM+w36x9wp9r+hf1JstMXtseXDtkiVoARAG6M959AA== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/networks@^5.7.0": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== @@ -2823,7 +2798,33 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.2": +"@ethersproject/providers@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.0.tgz#a885cfc7650a64385e7b03ac86fe9c2d4a9c2c63" + integrity sha512-+TTrrINMzZ0aXtlwO/95uhAggKm4USLm1PbeCBR/3XZ7+Oey+3pMyddzZEyRhizHpy1HXV0FRWRMI1O3EGYibA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/providers@^5.7.2": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== @@ -2952,7 +2953,18 @@ "@ethersproject/transactions" "^5.7.0" "@ethersproject/wordlists" "^5.7.0" -"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": +"@ethersproject/web@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.0.tgz#40850c05260edad8b54827923bbad23d96aac0bc" + integrity sha512-ApHcbbj+muRASVDSCl/tgxaH2LBkRMEYfLOLVa0COipx0+nlu0QKet7U2lEg0vdkh8XRSLf2nd1f1Uk9SrVSGA== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/web@^5.7.0": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== @@ -3403,41 +3415,6 @@ "@types/mdx" "^2.0.0" "@types/react" ">=16" -"@metamask/abi-utils@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@metamask/abi-utils/-/abi-utils-2.0.2.tgz#ad394e9cb8a95ac177cad942daadd88a246c0de8" - integrity sha512-B/A1dY/w4F/t6cDHUscklO6ovb/ztFsrsTXFd8QlqSByk/vyy+QbPE3VVpmmyI/7RX+PA1AJcvBdzCIz+r9dVQ== - dependencies: - "@metamask/utils" "^8.0.0" - superstruct "^1.0.3" - -"@metamask/eth-sig-util@^7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-7.0.1.tgz#ad3227d6120f15f9293478de7dd9685a5c329586" - integrity sha512-59GSrMyFH2fPfu7nKeIQdZ150zxXNNhAQIUaFRUW+MGtVA4w/ONbiQobcRBLi+jQProfIyss51G8pfLPcQ0ylg== - dependencies: - "@ethereumjs/util" "^8.1.0" - "@metamask/abi-utils" "^2.0.2" - "@metamask/utils" "^8.1.0" - ethereum-cryptography "^2.1.2" - tweetnacl "^1.0.3" - tweetnacl-util "^0.15.1" - -"@metamask/utils@^8.0.0", "@metamask/utils@^8.1.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-8.4.0.tgz#f44812c96467a4e1b70b2edff6ee89a9caa4e354" - integrity sha512-dbIc3C7alOe0agCuBHM1h71UaEaEqOk2W8rAtEn8QGz4haH2Qq7MoK6i7v2guzvkJVVh79c+QCzIqphC3KvrJg== - dependencies: - "@ethereumjs/tx" "^4.2.0" - "@noble/hashes" "^1.3.1" - "@scure/base" "^1.1.3" - "@types/debug" "^4.1.7" - debug "^4.3.4" - pony-cause "^2.1.10" - semver "^7.5.4" - superstruct "^1.0.3" - uuid "^9.0.1" - "@metaverse-network-sdk/type-definitions@0.0.1-16": version "0.0.1-16" resolved "https://registry.yarnpkg.com/@metaverse-network-sdk/type-definitions/-/type-definitions-0.0.1-16.tgz#43f85125064cbd199f0b33e47990debd15e7fdbb" @@ -3579,13 +3556,6 @@ dependencies: "@noble/hashes" "1.3.2" -"@noble/curves@1.3.0", "@noble/curves@~1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" - integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== - dependencies: - "@noble/hashes" "1.3.3" - "@noble/hashes@1.3.1": version "1.3.1" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" @@ -3596,16 +3566,11 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== -"@noble/hashes@1.3.3", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2": +"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== -"@noble/hashes@^1.3.1": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" - integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -4745,11 +4710,6 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== -"@scure/base@^1.1.3", "@scure/base@~1.1.4": - version "1.1.6" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" - integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== - "@scure/base@~1.1.0", "@scure/base@~1.1.2": version "1.1.6" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" @@ -4764,15 +4724,6 @@ "@noble/hashes" "~1.3.2" "@scure/base" "~1.1.2" -"@scure/bip32@1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.3.tgz#a9624991dc8767087c57999a5d79488f48eae6c8" - integrity sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ== - dependencies: - "@noble/curves" "~1.3.0" - "@noble/hashes" "~1.3.2" - "@scure/base" "~1.1.4" - "@scure/bip39@1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a" @@ -4781,14 +4732,6 @@ "@noble/hashes" "~1.3.0" "@scure/base" "~1.1.0" -"@scure/bip39@1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.2.tgz#f3426813f4ced11a47489cbcf7294aa963966527" - integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA== - dependencies: - "@noble/hashes" "~1.3.2" - "@scure/base" "~1.1.4" - "@sinclair/typebox@^0.25.16": version "0.25.24" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" @@ -6504,13 +6447,6 @@ resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.0.tgz#e2505f1c21ec08bda8915238e397fb71d2fc54ce" integrity sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g== -"@types/debug@^4.1.7": - version "4.1.12" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" - integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== - dependencies: - "@types/ms" "*" - "@types/detect-port@^1.3.0": version "1.3.3" resolved "https://registry.yarnpkg.com/@types/detect-port/-/detect-port-1.3.3.tgz#124c5d4c283f48a21f80826bcf39433b3e64aa81" @@ -6681,11 +6617,6 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== -"@types/ms@*": - version "0.7.34" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" - integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== - "@types/node-fetch@^2.6.4": version "2.6.4" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.4.tgz#1bc3a26de814f6bf466b25aeb1473fa1afe6a660" @@ -8356,11 +8287,6 @@ cosmiconfig@^8.1.3, cosmiconfig@^8.2.0: parse-json "^5.0.0" path-type "^4.0.0" -crc-32@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" - integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== - create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -9430,25 +9356,15 @@ ethereum-blockies-base64@^1.0.2: dependencies: pnglib "0.0.1" -ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz#1352270ed3b339fe25af5ceeadcf1b9c8e30768a" - integrity sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA== - dependencies: - "@noble/curves" "1.3.0" - "@noble/hashes" "1.3.3" - "@scure/bip32" "1.3.3" - "@scure/bip39" "1.2.2" - ethers-decode-error@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ethers-decode-error/-/ethers-decode-error-1.0.0.tgz#85f044a74173914a1d4b5f9bac6a132c9bfd51af" integrity sha512-wWB9g3XZZ/sQwNhzo+/IVtiyH3s1I5bPi0wH7Hp7XTPJEN0Tx2+LwXDNBgspxCHV5T8aok3D0LTnC062ZNnceA== -ethers@^5.7.0: - version "5.7.2" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" - integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== +ethers@5.7.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.0.tgz#0055da174b9e076b242b8282638bc94e04b39835" + integrity sha512-5Xhzp2ZQRi0Em+0OkOcRHxPzCfoBfgtOQA+RUylSkuHbhTEaQklnYi2hsWbRgs3ztJsXVXd9VKBcO1ScWL8YfA== dependencies: "@ethersproject/abi" "5.7.0" "@ethersproject/abstract-provider" "5.7.0" @@ -9465,10 +9381,10 @@ ethers@^5.7.0: "@ethersproject/json-wallets" "5.7.0" "@ethersproject/keccak256" "5.7.0" "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" + "@ethersproject/networks" "5.7.0" "@ethersproject/pbkdf2" "5.7.0" "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.2" + "@ethersproject/providers" "5.7.0" "@ethersproject/random" "5.7.0" "@ethersproject/rlp" "5.7.0" "@ethersproject/sha2" "5.7.0" @@ -9478,7 +9394,7 @@ ethers@^5.7.0: "@ethersproject/transactions" "5.7.0" "@ethersproject/units" "5.7.0" "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" + "@ethersproject/web" "5.7.0" "@ethersproject/wordlists" "5.7.0" eventemitter3@^4.0.1, eventemitter3@^4.0.7: @@ -11463,11 +11379,6 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micro-ftch@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" - integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== - micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -12332,11 +12243,6 @@ pontem-types-bundle@1.0.15: "@polkadot/types" "^6.0.5" typescript "^4.4.3" -pony-cause@^2.1.10: - version "2.1.10" - resolved "https://registry.yarnpkg.com/pony-cause/-/pony-cause-2.1.10.tgz#828457ad6f13be401a075dbf14107a9057945174" - integrity sha512-3IKLNXclQgkU++2fSi93sQ6BznFuxSLB11HdvZQ6JW/spahf/P1pAHBQEahr20rs0htZW0UDkM1HmA+nZkXKsw== - postcss-loader@^7.2.4: version "7.3.3" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.3.3.tgz#6da03e71a918ef49df1bb4be4c80401df8e249dd" @@ -13310,13 +13216,6 @@ semver@^7.3.8: dependencies: lru-cache "^6.0.0" -semver@^7.5.4: - version "7.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" - semver@~7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" @@ -13829,11 +13728,6 @@ stylis@^4.3.0: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.0.tgz#abe305a669fc3d8777e10eefcfc73ad861c5588c" integrity sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ== -superstruct@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.4.tgz#0adb99a7578bd2f1c526220da6571b2d485d91ca" - integrity sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ== - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -14132,16 +14026,6 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" -tweetnacl-util@^0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" - integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== - -tweetnacl@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -14415,11 +14299,6 @@ uuid@^9.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== -uuid@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" - integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== - v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" From d0dd1e1e5173e28a8f799d97aa83d4ecfe7b684b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Tue, 30 Apr 2024 16:29:56 +0200 Subject: [PATCH 084/103] Removed non added external tokens from recent trades, fixed router event check --- .../data/RecentTradesTableData.utils.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts b/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts index c12ee810c..a838d0291 100644 --- a/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts +++ b/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts @@ -37,25 +37,30 @@ export const useRecentTradesTableData = (assetId?: string) => { return Object.entries(groupedEvents) .map(([, value]) => { // check if last event is Router event - const routerEvent = - value[value.length - 1]?.name === "Router.Executed" - ? value[value.length - 1] - : null - + const routerEvent = value.find(({ name }) => name === "Router.Executed") const [firstEvent] = value + if (firstEvent?.name === "Router.Executed") return null if (!routerEvent) return firstEvent - return { + + const event = { ...firstEvent, args: { ...firstEvent.args, ...routerEvent.args, }, } + + const assetInMeta = assets.getAsset(event.args.assetIn.toString()) + const assetOutMeta = assets.getAsset(event.args.assetOut.toString()) + + if (!assetInMeta?.name || !assetOutMeta?.name) return null + + return event }) .filter(isNotNil) .slice(0, EVENTS_LIMIT) - }, [allTrades.data]) + }, [allTrades.data, assets]) const assetIds = events ? events?.map(({ args }) => args.assetIn.toString()) From 73a9ba8a78443f5c1b8f7ef15af7fe0f02aa3424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Tue, 30 Apr 2024 16:55:36 +0200 Subject: [PATCH 085/103] address pr comments --- .../modal/Web3ConnectWalletLoader.styled.ts | 20 ++++++++++++++++ .../modal/Web3ConnectWalletLoader.tsx | 23 ++++--------------- .../providers/Web3ConnectWCSelector.tsx | 6 +---- 3 files changed, 26 insertions(+), 23 deletions(-) create mode 100644 src/sections/web3-connect/modal/Web3ConnectWalletLoader.styled.ts diff --git a/src/sections/web3-connect/modal/Web3ConnectWalletLoader.styled.ts b/src/sections/web3-connect/modal/Web3ConnectWalletLoader.styled.ts new file mode 100644 index 000000000..b3e792a8b --- /dev/null +++ b/src/sections/web3-connect/modal/Web3ConnectWalletLoader.styled.ts @@ -0,0 +1,20 @@ +import styled from "@emotion/styled" + +export const SContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; +` + +export const SContent = styled.div` + display: grid; + grid-template-columns: 1fr; + + align-items: center; + justify-items: center; + + > * { + grid-column: 1; + grid-row: 1; + } +` diff --git a/src/sections/web3-connect/modal/Web3ConnectWalletLoader.tsx b/src/sections/web3-connect/modal/Web3ConnectWalletLoader.tsx index efbe29b6a..8b901e320 100644 --- a/src/sections/web3-connect/modal/Web3ConnectWalletLoader.tsx +++ b/src/sections/web3-connect/modal/Web3ConnectWalletLoader.tsx @@ -1,4 +1,3 @@ -import { css } from "@emotion/react" import { Text } from "components/Typography/Text/Text" import { useTranslation } from "react-i18next" import { @@ -7,6 +6,7 @@ import { } from "sections/web3-connect/Web3Connect.utils" import { FC } from "react" import { Spinner } from "components/Spinner/Spinner" +import { SContainer, SContent } from "./Web3ConnectWalletLoader.styled" type Props = { provider: WalletProviderType } @@ -14,21 +14,8 @@ export const Web3ConnectWalletLoader: FC = ({ provider }) => { const { t } = useTranslation() const { wallet } = getWalletProviderByType(provider) return ( -
-
* { - grid-column: 1; - grid-row: 1; - } - `} - > + + = ({ provider }) => { width={48} height={48} /> -
+ = ({ provider }) => { })}
-
+ ) } diff --git a/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx b/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx index 2a15925f9..5c62b0305 100644 --- a/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx +++ b/src/sections/web3-connect/providers/Web3ConnectWCSelector.tsx @@ -13,17 +13,13 @@ import { import { WalletConnect } from "sections/web3-connect/wallets/WalletConnect" import { isEvmAccount } from "utils/evm" -export type Web3ConnectWCSelectorProps = {} - const walletConnectType = WalletProviderType.WalletConnect const getWalletConnect = () => { return getWalletProviderByType(walletConnectType).wallet as WalletConnect } -export const Web3ConnectWCSelector: React.FC< - Web3ConnectWCSelectorProps -> = () => { +export const Web3ConnectWCSelector = () => { const { setStatus, setError, provider, status, account, mode } = useWeb3ConnectStore() From d27be80693faf12ae9a14b7281ae1f3bde376184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Tue, 30 Apr 2024 18:02:16 +0200 Subject: [PATCH 086/103] construct event without router --- src/api/volume.ts | 2 ++ .../data/RecentTradesTableData.utils.ts | 34 ++++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/api/volume.ts b/src/api/volume.ts index 687a0bed8..72d1e97bd 100644 --- a/src/api/volume.ts +++ b/src/api/volume.ts @@ -22,9 +22,11 @@ export type TradeType = { who: string assetIn: number assetOut: number + amount?: string amountIn: string amountOut: string } + block: { timestamp: string } diff --git a/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts b/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts index a838d0291..61418ee9d 100644 --- a/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts +++ b/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts @@ -9,7 +9,7 @@ import { isHydraAddress } from "utils/formatting" import { decodeAddress, encodeAddress } from "@polkadot/util-crypto" import { HYDRA_ADDRESS_PREFIX } from "utils/api" import { useAccountsIdentity } from "api/stats" -import { useAllTrades } from "api/volume" +import { TradeType, useAllTrades } from "api/volume" import { groupBy } from "utils/rx" import { isNotNil } from "utils/helpers" import { BN_NAN } from "utils/constants" @@ -41,14 +41,28 @@ export const useRecentTradesTableData = (assetId?: string) => { const [firstEvent] = value if (firstEvent?.name === "Router.Executed") return null - if (!routerEvent) return firstEvent - - const event = { - ...firstEvent, - args: { - ...firstEvent.args, - ...routerEvent.args, - }, + + let event: TradeType + if (!routerEvent) { + const lastEvent = value[value.length - 1] + event = { + ...firstEvent, + args: { + who: firstEvent.args.who, + assetIn: firstEvent.args.assetIn, + assetOut: lastEvent.args.assetOut, + amountIn: firstEvent.args.amount || firstEvent.args.amountIn, + amountOut: lastEvent.args.amount || lastEvent.args.amountOut, + }, + } + } else { + event = { + ...firstEvent, + args: { + ...firstEvent.args, + ...routerEvent.args, + }, + } } const assetInMeta = assets.getAsset(event.args.assetIn.toString()) @@ -62,6 +76,8 @@ export const useRecentTradesTableData = (assetId?: string) => { .slice(0, EVENTS_LIMIT) }, [allTrades.data, assets]) + console.log(events) + const assetIds = events ? events?.map(({ args }) => args.assetIn.toString()) : [] From 769962e4dcb6be400a776927abbc0cd75b1a16e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Tue, 30 Apr 2024 18:03:48 +0200 Subject: [PATCH 087/103] removed debug --- .../RecentTradesTable/data/RecentTradesTableData.utils.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts b/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts index 61418ee9d..9e07c0ca0 100644 --- a/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts +++ b/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts @@ -76,8 +76,6 @@ export const useRecentTradesTableData = (assetId?: string) => { .slice(0, EVENTS_LIMIT) }, [allTrades.data, assets]) - console.log(events) - const assetIds = events ? events?.map(({ args }) => args.assetIn.toString()) : [] From 3a6745b44e8d636bbc5e4a849b7ce22f51bc5737 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Fri, 3 May 2024 18:00:15 +0200 Subject: [PATCH 088/103] fix issues --- src/utils/farms/deposit.tsx | 96 +++++++++++++++++++++++-------------- src/utils/farms/exit.ts | 3 ++ 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/utils/farms/deposit.tsx b/src/utils/farms/deposit.tsx index b2d2dc343..c23f3e65d 100644 --- a/src/utils/farms/deposit.tsx +++ b/src/utils/farms/deposit.tsx @@ -6,6 +6,8 @@ import { ToastMessage, useStore } from "state/store" import { useRpcProvider } from "providers/rpcProvider" import { TOAST_MESSAGES } from "state/toasts" import { scale } from "utils/balance" +import { useAccount } from "sections/web3-connect/Web3Connect.utils" +import { isEvmAccount } from "utils/evm" export type FarmDepositMutationType = ReturnType @@ -19,6 +21,8 @@ export const useFarmDepositMutation = ( const { createTransaction } = useStore() const { api, assets } = useRpcProvider() const { t } = useTranslation() + const { account } = useAccount() + const isEvm = isEvmAccount(account?.address) const meta = assets.getAsset(poolId) const isXYK = assets.isShareToken(meta) @@ -80,47 +84,69 @@ export const useFarmDepositMutation = ( }, ) + const executeSecondMutation = async (depositId: string) => { + const secondStep: StepProps[] = [ + { + label: t("farms.modal.join.step", { number: 1 }), + state: "done", + }, + { + label: t("farms.modal.join.step", { number: 2 }), + state: "active", + }, + ] + + const txs = restFarm.map((farm) => + isXYK + ? api.tx.xykLiquidityMining.redepositShares( + farm.globalFarm.id, + farm.yieldFarm.id, + { assetIn: meta.assets[0], assetOut: meta.assets[1] }, + depositId, + ) + : api.tx.omnipoolLiquidityMining.redepositShares( + farm.globalFarm.id, + farm.yieldFarm.id, + depositId, + ), + ) + + if (txs.length > 0) { + await createTransaction( + { + tx: txs.length > 1 ? api.tx.utility.batch(txs) : txs[0], + }, + { toast, steps: secondStep }, + ) + } + } + + if (isEvm) { + const nftId = isXYK + ? await api.consts.xykLiquidityMining.nftCollectionId + : await api.consts.omnipoolLiquidityMining.nftCollectionId + + const positions = await api.query.uniques.account.entries( + account?.address, + nftId, + ) + + const depositId = positions + .map((position) => position[0].args[2].toNumber()) + .sort((a, b) => b - a)[0] + .toString() + + if (depositId) await executeSecondMutation(depositId) + } + for (const record of firstDeposit.events) { if ( api.events.omnipoolLiquidityMining.SharesDeposited.is(record.event) || api.events.xykLiquidityMining.SharesDeposited.is(record.event) ) { - const depositId = record.event.data.depositId - - const secondStep: StepProps[] = [ - { - label: t("farms.modal.join.step", { number: 1 }), - state: "done", - }, - { - label: t("farms.modal.join.step", { number: 2 }), - state: "active", - }, - ] - - const txs = restFarm.map((farm) => - isXYK - ? api.tx.xykLiquidityMining.redepositShares( - farm.globalFarm.id, - farm.yieldFarm.id, - { assetIn: meta.assets[0], assetOut: meta.assets[1] }, - depositId, - ) - : api.tx.omnipoolLiquidityMining.redepositShares( - farm.globalFarm.id, - farm.yieldFarm.id, - depositId, - ), - ) + const depositId = record.event.data.depositId.toString() - if (txs.length > 0) { - await createTransaction( - { - tx: txs.length > 1 ? api.tx.utility.batch(txs) : txs[0], - }, - { toast, steps: secondStep }, - ) - } + await executeSecondMutation(depositId) } } }, diff --git a/src/utils/farms/exit.ts b/src/utils/farms/exit.ts index 1a3966871..afddd251b 100644 --- a/src/utils/farms/exit.ts +++ b/src/utils/farms/exit.ts @@ -53,6 +53,9 @@ export const useFarmExitAllMutation = ( }, { onSuccess: () => { + queryClient.refetchQueries( + QUERY_KEYS.tokenBalance(meta.id, account?.address), + ) queryClient.refetchQueries( QUERY_KEYS.accountOmnipoolPositions(account?.address), ) From f9edd7f03a7a3837edd38bbe185317667227469c Mon Sep 17 00:00:00 2001 From: vkulinich Date: Fri, 3 May 2024 18:00:52 +0200 Subject: [PATCH 089/103] minor change --- src/utils/farms/deposit.tsx | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/utils/farms/deposit.tsx b/src/utils/farms/deposit.tsx index c23f3e65d..cd819ec3d 100644 --- a/src/utils/farms/deposit.tsx +++ b/src/utils/farms/deposit.tsx @@ -137,16 +137,18 @@ export const useFarmDepositMutation = ( .toString() if (depositId) await executeSecondMutation(depositId) - } - - for (const record of firstDeposit.events) { - if ( - api.events.omnipoolLiquidityMining.SharesDeposited.is(record.event) || - api.events.xykLiquidityMining.SharesDeposited.is(record.event) - ) { - const depositId = record.event.data.depositId.toString() - - await executeSecondMutation(depositId) + } else { + for (const record of firstDeposit.events) { + if ( + api.events.omnipoolLiquidityMining.SharesDeposited.is( + record.event, + ) || + api.events.xykLiquidityMining.SharesDeposited.is(record.event) + ) { + const depositId = record.event.data.depositId.toString() + + await executeSecondMutation(depositId) + } } } }, From 82a0900f8a7550ef725e4f2e4b666d8325560150 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Tue, 7 May 2024 14:50:20 +0200 Subject: [PATCH 090/103] Fix slow loading --- src/api/assetDetails.ts | 32 ++++++++++++------- .../Layout/Header/menu/HeaderMenu.tsx | 24 +++++++------- src/sections/assets/AssetsModal.tsx | 6 +--- src/sections/pools/header/VolumeTotal.tsx | 2 +- src/sections/pools/navigation/Navigation.tsx | 22 +++++++------ 5 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/api/assetDetails.ts b/src/api/assetDetails.ts index f14c8e9df..5bee0c5b0 100644 --- a/src/api/assetDetails.ts +++ b/src/api/assetDetails.ts @@ -161,12 +161,16 @@ export const getAssets = async (api: ApiPromise) => { rawAssetsData, rawAssetsLocations, hubAssetId, + poolAddresses, + xykPoolAssets, isReferralsEnabled, ] = await Promise.all([ api.rpc.system.properties(), api.query.assetRegistry.assets.entries(), api.query.assetRegistry.assetLocations.entries(), api.consts.omnipool.hubAssetId, + api.query.xyk.shareToken.entries(), + api.query.xyk.poolAssets.entries(), api.query.referrals, ]) @@ -193,7 +197,7 @@ export const getAssets = async (api: ApiPromise) => { //@ts-ignore const isExternal = assetType === "External" //@ts-ignore - const isSufficient = data.isSufficient.toPrimitive() + const isSufficient = data.isSufficient?.toPrimitive() ?? false let meta if (rawAssetsMeta) { @@ -369,7 +373,6 @@ export const getAssets = async (api: ApiPromise) => { stableswap.push(asset) } } else if (isShareToken) { - const poolAddresses = await api.query.xyk.shareToken.entries() const poolAddress = poolAddresses .find( (poolAddress) => poolAddress[1].toString() === assetCommon.id, @@ -377,16 +380,21 @@ export const getAssets = async (api: ApiPromise) => { .args[0].toString() if (poolAddress) { - const poolAssets = await api.query.xyk.poolAssets(poolAddress) - const assets = poolAssets - .unwrap() - .map((poolAsset) => poolAsset.toString()) + const poolAssets = xykPoolAssets.find( + (xykPool) => xykPool[0].args[0].toString() === poolAddress, + )?.[1] - shareTokensRaw.push({ - ...assetCommon, - assets, - poolAddress, - }) + if (poolAssets) { + const assets = poolAssets + .unwrap() + .map((poolAsset) => poolAsset.toString()) + + shareTokensRaw.push({ + ...assetCommon, + assets, + poolAddress, + }) + } } } else if (isExternal) { const location = rawAssetsLocations.find( @@ -432,6 +440,8 @@ export const getAssets = async (api: ApiPromise) => { const shareTokens = shareTokensRaw.reduce>( (acc, shareToken) => { + if (!shareToken.assets) return acc + const [assetAId, assetBId] = shareToken.assets const assetA = [...tokens, ...bonds, ...external].find( diff --git a/src/components/Layout/Header/menu/HeaderMenu.tsx b/src/components/Layout/Header/menu/HeaderMenu.tsx index 81420e01b..85b0dce76 100644 --- a/src/components/Layout/Header/menu/HeaderMenu.tsx +++ b/src/components/Layout/Header/menu/HeaderMenu.tsx @@ -7,7 +7,7 @@ import { forwardRef } from "react" import { useRpcProvider } from "providers/rpcProvider" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { useAccountOmnipoolPositions } from "sections/pools/PoolsPage.utils" -import { useTokensBalances } from "api/balances" +import { useAccountBalances } from "api/accountBalances" export const HeaderMenu = forwardRef((_, ref) => { const { t } = useTranslation() @@ -77,24 +77,26 @@ const LiquidityMenuItem = ({ const { assets } = useRpcProvider() const accountPositions = useAccountOmnipoolPositions() - const shareTokensId = assets.shareTokens.map((shareToken) => shareToken.id) - const stableswapsId = assets.stableswap.map((shareToken) => shareToken.id) + const balances = useAccountBalances(account?.address) - const userPositions = useTokensBalances( - [...shareTokensId, ...stableswapsId], - account?.address, - ) + const isPoolBalances = balances.data?.balances.some((balance) => { + if (balance.freeBalance.gt(0)) { + const meta = assets.getAsset(balance.id) + return meta.isStableSwap || meta.isShareToken + } + return false + }) - const isOmnipoolPositions = + const isPositions = accountPositions.data?.miningNfts.length || accountPositions.data?.omnipoolNfts.length || - userPositions.some((userPosition) => userPosition.data?.freeBalance.gt(0)) + isPoolBalances return ( {({ isActive }) => ( diff --git a/src/sections/assets/AssetsModal.tsx b/src/sections/assets/AssetsModal.tsx index 64a56dddb..2308cc2cb 100644 --- a/src/sections/assets/AssetsModal.tsx +++ b/src/sections/assets/AssetsModal.tsx @@ -27,7 +27,6 @@ type Props = { allAssets?: boolean withBonds?: boolean withExternal?: boolean - withShareTokens?: boolean confirmRequired?: boolean defaultSelectedAsssetId?: string } @@ -40,7 +39,6 @@ export const AssetsModalContent = ({ hideInactiveAssets, allAssets, withBonds, - withShareTokens, confirmRequired, defaultSelectedAsssetId, withExternal, @@ -79,14 +77,12 @@ export const AssetsModalContent = ({ ...assets.tokens, ...assets.stableswap, ...(withExternal ? assets.external.filter((token) => token.name) : []), - ...(withShareTokens ? assets.shareTokens : []), ]) : accountAssets.filter( (accountAsset): accountAsset is { balance: TBalance; asset: TToken } => accountAsset.asset.isToken || accountAsset.asset.isStableSwap || - (withExternal ? accountAsset.asset.isExternal : false) || - (withShareTokens ? accountAsset.asset.isShareToken : false), + (withExternal ? accountAsset.asset.isExternal : false), ) const bonds = allAssets diff --git a/src/sections/pools/header/VolumeTotal.tsx b/src/sections/pools/header/VolumeTotal.tsx index 78290765b..9993cf3d4 100644 --- a/src/sections/pools/header/VolumeTotal.tsx +++ b/src/sections/pools/header/VolumeTotal.tsx @@ -26,7 +26,7 @@ export const AllPoolsVolumeTotal = () => { !!pools.data?.some((pool) => pool.isVolumeLoading) const totalVolumes = pools.data?.reduce( - (memo, pool) => memo.plus(pool.volume ?? BN_0), + (memo, pool) => memo.plus(!pool.volume.isNaN() ? pool.volume : BN_0), BN_0, ) diff --git a/src/sections/pools/navigation/Navigation.tsx b/src/sections/pools/navigation/Navigation.tsx index 572965d9d..041b876bb 100644 --- a/src/sections/pools/navigation/Navigation.tsx +++ b/src/sections/pools/navigation/Navigation.tsx @@ -8,7 +8,6 @@ import { SSeparator } from "components/Separator/Separator.styled" import { useAccountOmnipoolPositions } from "sections/pools/PoolsPage.utils" import { useRpcProvider } from "providers/rpcProvider" import { useTranslation } from "react-i18next" -import { useTokensBalances } from "api/balances" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { SubNavigation, @@ -17,6 +16,7 @@ import { import { BackSubHeader } from "components/Layout/Header/BackSubHeader/BackSubHeader" import { useLocation } from "@tanstack/react-location" import { t } from "i18next" +import { useAccountBalances } from "api/accountBalances" const routeMap = new Map([ [LINKS.allPools, t("liquidity.navigation.allPools")], @@ -57,20 +57,22 @@ const MyLiquidity = () => { const { assets } = useRpcProvider() const accountPositions = useAccountOmnipoolPositions() - const shareTokensId = assets.shareTokens.map((shareToken) => shareToken.id) - const stableswapsId = assets.stableswap.map((shareToken) => shareToken.id) + const balances = useAccountBalances(account?.address) - const userPositions = useTokensBalances( - [...shareTokensId, ...stableswapsId], - account?.address, - ) + const isPoolBalances = balances.data?.balances.some((balance) => { + if (balance.freeBalance.gt(0)) { + const meta = assets.getAsset(balance.id) + return meta.isStableSwap || meta.isShareToken + } + return false + }) - const isOmnipoolPositions = + const isPositions = accountPositions.data?.miningNfts.length || accountPositions.data?.omnipoolNfts.length || - userPositions.some((userPosition) => userPosition.data?.freeBalance.gt(0)) + isPoolBalances - if (!isOmnipoolPositions) return null + if (!isPositions) return null return ( <> From d1c8fb0120301dd1b40277f5573d655bfa1373f4 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Wed, 8 May 2024 15:23:48 +0200 Subject: [PATCH 091/103] Hide xyk pools --- src/i18n/locales/en/translations.json | 1 + src/sections/pools/PoolsPage.utils.ts | 2 ++ src/sections/pools/sections/AllPools.tsx | 34 ++++++++++++++++--- src/sections/pools/sections/IsolatedPools.tsx | 25 ++++++++++++-- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/i18n/locales/en/translations.json b/src/i18n/locales/en/translations.json index 43cb05106..0425c4e84 100644 --- a/src/i18n/locales/en/translations.json +++ b/src/i18n/locales/en/translations.json @@ -168,6 +168,7 @@ "liquidity.pool.details.price": "{{symbol}} Price", "liquidity.section.omnipoolAndStablepool": "Omnipool + Stablepool", "liquidity.section.xyk": "Isolated pools", + "liquidity.section.xyk.toggle": "Show low liquidity pools", "liquidity.asset.title": "Asset", "liquidity.assets.title": "Assets", "liquidity.asset.details.fee": "Fee", diff --git a/src/sections/pools/PoolsPage.utils.ts b/src/sections/pools/PoolsPage.utils.ts index 950125c67..b4280a186 100644 --- a/src/sections/pools/PoolsPage.utils.ts +++ b/src/sections/pools/PoolsPage.utils.ts @@ -45,6 +45,8 @@ import { import { Option } from "@polkadot/types" import { PalletLiquidityMiningDepositData } from "@polkadot/types/lookup" +export const XYK_TVL_VISIBILITY = 5000 + export const useAssetsTradability = () => { const { assets: { hub }, diff --git a/src/sections/pools/sections/AllPools.tsx b/src/sections/pools/sections/AllPools.tsx index 651e8ac35..5c449e03c 100644 --- a/src/sections/pools/sections/AllPools.tsx +++ b/src/sections/pools/sections/AllPools.tsx @@ -1,7 +1,11 @@ import { useRpcProvider } from "providers/rpcProvider" -import { useMemo } from "react" +import { useMemo, useState } from "react" import { useTranslation } from "react-i18next" -import { usePools, useXYKPools } from "sections/pools/PoolsPage.utils" +import { + usePools, + useXYKPools, + XYK_TVL_VISIBILITY, +} from "sections/pools/PoolsPage.utils" import { HeaderValues } from "sections/pools/header/PoolsHeader" import { HeaderTotalData } from "sections/pools/header/PoolsHeaderTotal" import { BN_0 } from "utils/constants" @@ -18,6 +22,7 @@ import { PoolSkeleton } from "sections/pools/pool/PoolSkeleton" import { EmptySearchState } from "components/EmptySearchState/EmptySearchState" import { TableLabel } from "sections/pools/components/TableLabel" import { CreateXYKPoolModalButton } from "sections/pools/modals/CreateXYKPool/CreateXYKPoolModalButton" +import { Switch } from "components/Switch/Switch" export const AllPools = () => { const { t } = useTranslation() @@ -86,6 +91,7 @@ const AllPoolsData = () => { const pools = usePools() const xylPools = useXYKPools() + const [showAllXyk, setShowAllXyk] = useState(false) const omnipoolTotal = useMemo( () => @@ -198,7 +204,18 @@ const AllPoolsData = () => { align: ["flex-start", "flex-end"], }} > - +
+ + setShowAllXyk(value)} + size="small" + name="showAll" + label={t("liquidity.section.xyk.toggle")} + sx={{ pb: 20 }} + /> +
+ { {xylPools.isInitialLoading ? ( ) : ( - + + pool.tvlDisplay.gte(XYK_TVL_VISIBILITY), + ) + } + isXyk + /> )}
) : null} diff --git a/src/sections/pools/sections/IsolatedPools.tsx b/src/sections/pools/sections/IsolatedPools.tsx index 14b181293..ba43efc5f 100644 --- a/src/sections/pools/sections/IsolatedPools.tsx +++ b/src/sections/pools/sections/IsolatedPools.tsx @@ -1,9 +1,9 @@ import { useRpcProvider } from "providers/rpcProvider" -import { useXYKPools } from "sections/pools/PoolsPage.utils" +import { useXYKPools, XYK_TVL_VISIBILITY } from "sections/pools/PoolsPage.utils" import { HeaderValues } from "sections/pools/header/PoolsHeader" import { HeaderTotalData } from "sections/pools/header/PoolsHeaderTotal" import { useTranslation } from "react-i18next" -import { useMemo } from "react" +import { useMemo, useState } from "react" import { BN_0 } from "utils/constants" import { SearchFilter } from "sections/pools/filter/SearchFilter" import { useSearchFilter } from "sections/pools/filter/SearchFilter.utils" @@ -17,6 +17,7 @@ import { PoolSkeleton } from "sections/pools/pool/PoolSkeleton" import { EmptySearchState } from "components/EmptySearchState/EmptySearchState" import { Spacer } from "components/Spacer/Spacer" import { CreateXYKPoolModalButton } from "sections/pools/modals/CreateXYKPool/CreateXYKPoolModalButton" +import { Switch } from "components/Switch/Switch" export const IsolatedPools = () => { const { t } = useTranslation() @@ -58,6 +59,7 @@ export const IsolatedPools = () => { const IsolatedPoolsData = () => { const { t } = useTranslation() + const [showAllXyk, setShowAllXyk] = useState(false) const { search } = useSearchFilter() const { id } = useSearch<{ Search: { @@ -117,6 +119,14 @@ const IsolatedPoolsData = () => {
+ setShowAllXyk(value)} + size="small" + name="showAll" + label={t("liquidity.section.xyk.toggle")} + sx={{ pb: 20 }} + /> { {xykPools.isInitialLoading ? ( ) : filteredPools.length ? ( - + + pool.tvlDisplay.gte(XYK_TVL_VISIBILITY), + ) + } + isXyk + /> ) : ( )} From 13b5fe476b41e6921605e012a2ce7899ac4d5660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Thu, 9 May 2024 10:56:36 +0200 Subject: [PATCH 092/103] Update permit contract, use permit correctly for changing fee payment asset --- src/sections/transaction/ReviewTransactionForm.tsx | 7 +++---- .../transaction/ReviewTransactionForm.utils.tsx | 14 +++++++------- .../wallets/MetaMask/MetaMaskSigner.ts | 4 +++- src/utils/evm.ts | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/sections/transaction/ReviewTransactionForm.tsx b/src/sections/transaction/ReviewTransactionForm.tsx index e8ecb416a..83227752e 100644 --- a/src/sections/transaction/ReviewTransactionForm.tsx +++ b/src/sections/transaction/ReviewTransactionForm.tsx @@ -68,7 +68,6 @@ export const ReviewTransactionForm: FC = (props) => { acceptedFeePaymentAssets, isEnoughPaymentBalance, feePaymentMeta, - originalFeePaymentMeta, isLinkedAccount, storedReferralCode, tx, @@ -94,8 +93,7 @@ export const ReviewTransactionForm: FC = (props) => { if (!wallet.signer) throw new Error("Missing signer") if (wallet?.signer instanceof MetaMaskSigner) { - const shouldUsePermit = - originalFeePaymentMeta?.id !== NATIVE_EVM_ASSET_ID + const shouldUsePermit = feePaymentMeta?.id !== NATIVE_EVM_ASSET_ID if (shouldUsePermit) { const permit = await wallet.signer.sendPermitDispatch( tx.method.toHex(), @@ -115,7 +113,8 @@ export const ReviewTransactionForm: FC = (props) => { ) .send() // @TODO handle permit result - console.log({ res }) + const hash = res.toHex() + console.log({ hash }) return } diff --git a/src/sections/transaction/ReviewTransactionForm.utils.tsx b/src/sections/transaction/ReviewTransactionForm.utils.tsx index 69b3be2ee..374ff55bc 100644 --- a/src/sections/transaction/ReviewTransactionForm.utils.tsx +++ b/src/sections/transaction/ReviewTransactionForm.utils.tsx @@ -11,7 +11,11 @@ import { useAssetsModal } from "sections/assets/AssetsModal.utils" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { BN_1 } from "utils/constants" import { useRpcProvider } from "providers/rpcProvider" -import { NATIVE_EVM_ASSET_DECIMALS, isEvmAccount } from "utils/evm" +import { + NATIVE_EVM_ASSET_DECIMALS, + NATIVE_EVM_ASSET_ID, + isEvmAccount, +} from "utils/evm" import { BN_NAN } from "utils/constants" import { useUserReferrer } from "api/referrals" import { HYDRADX_CHAIN_KEY } from "sections/xcm/XcmPage.utils" @@ -39,7 +43,8 @@ export const useTransactionValues = ({ const { fee, currencyId: feePaymentId, feeExtra } = overrides ?? {} - const isEvm = isEvmAccount(account?.address) + const shouldUseEvmPermit = feePaymentId !== NATIVE_EVM_ASSET_ID + const isEvm = !shouldUseEvmPermit && isEvmAccount(account?.address) const evmPaymentFee = useEvmPaymentFee( tx.method.toHex(), isEvm ? account?.address : "", @@ -90,10 +95,6 @@ export const useTransactionValues = ({ ? assets.getAsset(accountFeePaymentId) : undefined - const originalFeePaymentMeta = feePaymentAssetId - ? assets.getAsset(feePaymentAssetId) - : undefined - const spotPrice = useSpotPrice(assets.native.id, accountFeePaymentId) const feeAssetBalance = useTokenBalance(accountFeePaymentId, account?.address) @@ -135,7 +136,6 @@ export const useTransactionValues = ({ isEnoughPaymentBalance: false, displayFeePaymentValue: BN_NAN, feePaymentMeta, - originalFeePaymentMeta, acceptedFeePaymentAssets: [], era, nonce: nonce.data, diff --git a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts index cbcc41a39..79cee5ee6 100644 --- a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts +++ b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts @@ -64,7 +64,9 @@ export class MetaMaskSigner { this.signer.provider, ) - return callPermit.nonces(this.address) + const nonces = await callPermit.nonces(this.address) + + return nonces } sendPermitDispatch = async ( diff --git a/src/utils/evm.ts b/src/utils/evm.ts index 8fef9ddce..9b31a3476 100644 --- a/src/utils/evm.ts +++ b/src/utils/evm.ts @@ -16,7 +16,7 @@ export const NATIVE_EVM_ASSET_ID = import.meta.env .VITE_EVM_NATIVE_ASSET_ID as string export const DISPATCH_ADDRESS = "0x0000000000000000000000000000000000000401" -export const CALL_PERMIT_ADDRESS = "0x0000000000000000000000000000000000000010" +export const CALL_PERMIT_ADDRESS = "0x000000000000000000000000000000000000080a" export const CALL_PERMIT_ABI = `[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"gaslimit","type":"uint64"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"dispatch","outputs":[{"internalType":"bytes","name":"output","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` export function isEvmAccount(address?: string) { From 1b45bbb193071bd107c04709cb7fedc630825ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Thu, 9 May 2024 14:54:17 +0200 Subject: [PATCH 093/103] Handle dispatch permit extrinsic status --- .../transaction/ReviewTransaction.tsx | 5 + .../transaction/ReviewTransaction.utils.tsx | 158 +++++++++++++++--- .../transaction/ReviewTransactionForm.tsx | 35 ++-- .../wallets/MetaMask/MetaMaskSigner.ts | 6 +- 4 files changed, 156 insertions(+), 48 deletions(-) diff --git a/src/sections/transaction/ReviewTransaction.tsx b/src/sections/transaction/ReviewTransaction.tsx index 2ad4cd0dc..a9074be6c 100644 --- a/src/sections/transaction/ReviewTransaction.tsx +++ b/src/sections/transaction/ReviewTransaction.tsx @@ -21,6 +21,7 @@ export const ReviewTransaction = (props: Transaction) => { const { sendTx, sendEvmTx, + sendPermitTx, isLoading, isSuccess, isError: isSendError, @@ -126,6 +127,10 @@ export const ReviewTransaction = (props: Transaction) => { props.onSubmitted?.() sendTx(signed) }} + onPermitDispatched={(permit) => { + props.onSubmitted?.() + sendPermitTx(permit) + }} onSignError={setSignError} /> ) : isEvmXCall(props.xcall) && props.xcallMeta ? ( diff --git a/src/sections/transaction/ReviewTransaction.utils.tsx b/src/sections/transaction/ReviewTransaction.utils.tsx index 71087c050..bfe46927d 100644 --- a/src/sections/transaction/ReviewTransaction.utils.tsx +++ b/src/sections/transaction/ReviewTransaction.utils.tsx @@ -3,6 +3,7 @@ import { TransactionResponse, } from "@ethersproject/providers" import { Hash } from "@open-web3/orml-types/interfaces" +import { ApiPromise } from "@polkadot/api" import { SubmittableExtrinsic } from "@polkadot/api/types" import type { AnyJson } from "@polkadot/types-codec/types" import { ExtrinsicStatus } from "@polkadot/types/interfaces" @@ -14,6 +15,7 @@ import { useRef, useState } from "react" import { useTranslation } from "react-i18next" import { useMountedState } from "react-use" import { useEvmAccount } from "sections/web3-connect/Web3Connect.utils" +import { PermitResult } from "sections/web3-connect/wallets/MetaMask/MetaMaskSigner" import { useToast } from "state/toasts" import { H160, getEvmChainById, getEvmTxLink, isEvmAccount } from "utils/evm" import { getSubscanLinkByType } from "utils/formatting" @@ -104,6 +106,43 @@ function evmTxReceiptToSubmittableResult(txReceipt: TransactionReceipt) { return submittableResult } + +const createResultOnCompleteHandler = + ( + api: ApiPromise, + { + onSuccess, + onError, + onSettled, + }: { + onSuccess: (result: ISubmittableResult) => void + onError: (error: Error) => void + onSettled: () => void + }, + ) => + (result: ISubmittableResult) => { + if (result.isCompleted) { + if (result.dispatchError) { + let errorMessage = result.dispatchError.toString() + + if (result.dispatchError.isModule) { + const decoded = api.registry.findMetaError( + result.dispatchError.asModule, + ) + errorMessage = `${decoded.section}.${ + decoded.method + }: ${decoded.docs.join(" ")}` + } + + onError(new Error(errorMessage)) + } else { + onSuccess(result) + } + + onSettled() + } + } + export const useSendEvmTransactionMutation = ( options: MutationObserverOptions< ISubmittableResult, @@ -160,6 +199,84 @@ export const useSendEvmTransactionMutation = ( } } +export const useSendDispatchPermit = ( + options: MutationObserverOptions< + ISubmittableResult, + unknown, + PermitResult + > = {}, +) => { + const { api } = useRpcProvider() + const [txState, setTxState] = useState(null) + const [txHash, setTxHash] = useState("") + const isMounted = useMountedState() + + const sendTx = useMutation(async (permit) => { + return await new Promise(async (resolve, reject) => { + try { + const unsubscribe = await api.tx.multiTransactionPayment + .dispatchPermit( + permit.message.from, + permit.message.to, + permit.message.value, + permit.message.data, + permit.message.gaslimit, + permit.message.deadline, + permit.signature.v, + permit.signature.r, + permit.signature.s, + ) + .send(async (result) => { + if (!result || !result.status) return + + const timeout = setTimeout(() => { + clearTimeout(timeout) + reject(new UnknownTransactionState()) + }, 60000) + + if (isMounted()) { + setTxHash(result.txHash.toHex()) + setTxState(result.status.type) + } else { + clearTimeout(timeout) + } + + const onComplete = createResultOnCompleteHandler(api, { + onError: (error) => { + clearTimeout(timeout) + reject(error) + }, + onSuccess: (result) => { + clearTimeout(timeout) + resolve(result) + }, + onSettled: unsubscribe, + }) + + return onComplete(result) + }) + } catch (err) { + reject(err?.toString() ?? "Unknown error") + } + }) + }, options) + + const txLink = txHash + ? `${getSubscanLinkByType("extrinsic")}/${txHash}` + : undefined + + return { + ...sendTx, + txState, + txLink, + reset: () => { + setTxState(null) + setTxHash("") + sendTx.reset() + }, + } +} + export const useSendTransactionMutation = ( options: MutationObserverOptions< ISubmittableResult, @@ -190,28 +307,19 @@ export const useSendTransactionMutation = ( clearTimeout(timeout) } - if (result.isCompleted) { - if (result.dispatchError) { - let errorMessage = result.dispatchError.toString() - - if (result.dispatchError.isModule) { - const decoded = api.registry.findMetaError( - result.dispatchError.asModule, - ) - errorMessage = `${decoded.section}.${ - decoded.method - }: ${decoded.docs.join(" ")}` - } - + const onComplete = createResultOnCompleteHandler(api, { + onError: (error) => { clearTimeout(timeout) - reject(new Error(errorMessage)) - } else { + reject(error) + }, + onSuccess: (result) => { clearTimeout(timeout) resolve(result) - } + }, + onSettled: unsubscribe, + }) - unsubscribe() - } + return onComplete(result) }) } catch (err) { reject(err?.toString() ?? "Unknown error") @@ -301,7 +409,9 @@ const useBoundReferralToast = () => { } export const useSendTx = () => { - const [txType, setTxType] = useState<"default" | "evm" | null>(null) + const [txType, setTxType] = useState<"default" | "evm" | "permit" | null>( + null, + ) const boundReferralToast = useBoundReferralToast() @@ -321,11 +431,19 @@ export const useSendTx = () => { onSuccess: boundReferralToast.onSuccess, }) - const activeMutation = txType === "default" ? sendTx : sendEvmTx + const sendPermitTx = useSendDispatchPermit({ + onMutate: () => { + setTxType("permit") + }, + }) + + const activeMutation = + txType === "default" ? sendTx : txType === "evm" ? sendEvmTx : sendPermitTx return { sendTx: sendTx.mutateAsync, sendEvmTx: sendEvmTx.mutateAsync, + sendPermitTx: sendPermitTx.mutateAsync, ...activeMutation, } } diff --git a/src/sections/transaction/ReviewTransactionForm.tsx b/src/sections/transaction/ReviewTransactionForm.tsx index 83227752e..511924a91 100644 --- a/src/sections/transaction/ReviewTransactionForm.tsx +++ b/src/sections/transaction/ReviewTransactionForm.tsx @@ -7,7 +7,10 @@ import { ModalScrollableContent } from "components/Modal/Modal" import { Text } from "components/Typography/Text/Text" import { useTranslation } from "react-i18next" import { useAccount, useWallet } from "sections/web3-connect/Web3Connect.utils" -import { MetaMaskSigner } from "sections/web3-connect/wallets/MetaMask/MetaMaskSigner" +import { + MetaMaskSigner, + PermitResult, +} from "sections/web3-connect/wallets/MetaMask/MetaMaskSigner" import { Transaction, useStore } from "state/store" import { theme } from "theme" import { ReviewTransactionData } from "./ReviewTransactionData" @@ -22,7 +25,6 @@ import { useReferralCodesStore } from "sections/referrals/store/useReferralCodes import BN from "bignumber.js" import { NATIVE_EVM_ASSET_ID, isEvmAccount } from "utils/evm" import { isSetCurrencyExtrinsic } from "sections/transaction/ReviewTransaction.utils" -import { useRpcProvider } from "providers/rpcProvider" type TxProps = Omit & { tx: SubmittableExtrinsic<"promise"> @@ -31,6 +33,7 @@ type TxProps = Omit & { type Props = TxProps & { title?: string onCancel: () => void + onPermitDispatched: (permit: PermitResult) => void onEvmSigned: (data: { evmTx: TransactionResponse tx: SubmittableExtrinsic<"promise"> @@ -43,7 +46,6 @@ export const ReviewTransactionForm: FC = (props) => { const { t } = useTranslation() const { account } = useAccount() const { setReferralCode } = useReferralCodesStore() - const { api } = useRpcProvider() const polkadotJSUrl = usePolkadotJSTxUrl(props.tx) @@ -93,32 +95,15 @@ export const ReviewTransactionForm: FC = (props) => { if (!wallet.signer) throw new Error("Missing signer") if (wallet?.signer instanceof MetaMaskSigner) { + const txData = tx.method.toHex() const shouldUsePermit = feePaymentMeta?.id !== NATIVE_EVM_ASSET_ID + if (shouldUsePermit) { - const permit = await wallet.signer.sendPermitDispatch( - tx.method.toHex(), - ) - - const res = await api.tx.multiTransactionPayment - .dispatchPermit( - permit.message.from, - permit.message.to, - permit.message.value, - permit.message.data, - permit.message.gaslimit, - permit.message.deadline, - permit.signature.v, - permit.signature.r, - permit.signature.s, - ) - .send() - // @TODO handle permit result - const hash = res.toHex() - console.log({ hash }) - return + const permit = await wallet.signer.getPermit(txData) + return props.onPermitDispatched(permit) } - const evmTx = await wallet.signer.sendDispatch(tx.method.toHex()) + const evmTx = await wallet.signer.sendDispatch(txData) return props.onEvmSigned({ evmTx, tx }) } diff --git a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts index 79cee5ee6..a6a727bd1 100644 --- a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts +++ b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts @@ -23,6 +23,8 @@ type PermitMessage = { deadline: number } +export type PermitResult = { signature: Signature; message: PermitMessage } + export class MetaMaskSigner { address: string provider: MetaMaskLikeProvider @@ -69,9 +71,7 @@ export class MetaMaskSigner { return nonces } - sendPermitDispatch = async ( - data: string, - ): Promise<{ signature: Signature; message: PermitMessage }> => { + getPermit = async (data: string): Promise => { if (this.provider && this.address) { const nonce = await this.getPermitNonce() const tx = { From 2683883cfa26186ae83918b8dd144cac8f2ec667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Thu, 9 May 2024 17:17:30 +0200 Subject: [PATCH 094/103] include stablepool events in recent trades --- src/api/volume.ts | 71 +++++++++++++++---- .../data/RecentTradesTableData.utils.ts | 44 ++++++++++-- 2 files changed, 95 insertions(+), 20 deletions(-) diff --git a/src/api/volume.ts b/src/api/volume.ts index 72d1e97bd..460862819 100644 --- a/src/api/volume.ts +++ b/src/api/volume.ts @@ -26,7 +26,23 @@ export type TradeType = { amountIn: string amountOut: string } + block: { + timestamp: string + } + extrinsic: { + hash: string + } +} +export type StableswapType = { + name: "Stableswap.LiquidityAdded" + id: string + args: { + who: string + poolId: number + assets: { amount: string; assetId: number }[] + amounts: { amount: string; assetId: number }[] + } block: { timestamp: string } @@ -35,6 +51,24 @@ export type TradeType = { } } +export const isStableswapEvent = ( + event: TradeType | StableswapType, +): event is StableswapType => + ["Stableswap.LiquidityAdded", "Stableswap.LiquidityRemoved"].includes( + event.name, + ) + +export const isTradeEvent = ( + event: TradeType | StableswapType, +): event is TradeType => + [ + "Omnipool.SellExecuted", + "Omnipool.BuyExecuted", + "XYK.SellExecuted", + "XYK.BuyExecuted", + "Router.Executed", + ].includes(event.name) + export const getTradeVolume = (indexerUrl: string, assetId: string) => async () => { const assetIn = Number(assetId) @@ -155,7 +189,7 @@ export const getAllTrades = // describe the event arguments at all return { ...(await request<{ - events: Array + events: Array }>( indexerUrl, gql` @@ -172,18 +206,29 @@ export const getAllTrades = args_jsonContains: { assetIn: $assetId } phase_eq: "ApplyExtrinsic" block: { timestamp_gte: $after } - OR: { - name_in: [ - "Omnipool.SellExecuted" - "Omnipool.BuyExecuted" - "XYK.SellExecuted" - "XYK.BuyExecuted" - "Router.Executed" - ] - args_jsonContains: { assetOut: $assetId } - phase_eq: "ApplyExtrinsic" - block: { timestamp_gte: $after } - } + OR: [ + { + name_in: [ + "Omnipool.SellExecuted" + "Omnipool.BuyExecuted" + "XYK.SellExecuted" + "XYK.BuyExecuted" + "Router.Executed" + ] + args_jsonContains: { assetOut: $assetId } + phase_eq: "ApplyExtrinsic" + block: { timestamp_gte: $after } + } + { + name_in: [ + "Stableswap.LiquidityAdded" + "Stableswap.LiquidityRemoved" + ] + args_jsonContains: { poolId: $assetId } + phase_eq: "ApplyExtrinsic" + block: { timestamp_gte: $after } + } + ] } orderBy: [block_height_DESC, pos_ASC] limit: 100 diff --git a/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts b/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts index 9e07c0ca0..a1dd60cf2 100644 --- a/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts +++ b/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts @@ -9,7 +9,12 @@ import { isHydraAddress } from "utils/formatting" import { decodeAddress, encodeAddress } from "@polkadot/util-crypto" import { HYDRA_ADDRESS_PREFIX } from "utils/api" import { useAccountsIdentity } from "api/stats" -import { TradeType, useAllTrades } from "api/volume" +import { + TradeType, + isStableswapEvent, + isTradeEvent, + useAllTrades, +} from "api/volume" import { groupBy } from "utils/rx" import { isNotNil } from "utils/helpers" import { BN_NAN } from "utils/constants" @@ -38,21 +43,46 @@ export const useRecentTradesTableData = (assetId?: string) => { .map(([, value]) => { // check if last event is Router event const routerEvent = value.find(({ name }) => name === "Router.Executed") - const [firstEvent] = value + const tradeEvents = value.filter(isTradeEvent) + const stableswapEvents = value.filter(isStableswapEvent) + const [firstEvent] = tradeEvents + if (!tradeEvents.length) return null if (firstEvent?.name === "Router.Executed") return null let event: TradeType if (!routerEvent) { - const lastEvent = value[value.length - 1] + const lastEvent = tradeEvents[tradeEvents.length - 1] + const assetIn = firstEvent.args.assetIn + const assetOut = lastEvent.args.assetOut + + const stableswapIn = stableswapEvents.find( + ({ args }) => args.poolId === assetIn, + ) + const stableswapAssetIn = stableswapIn?.args?.assets?.[0]?.assetId + const stableswapAmountIn = stableswapIn?.args?.assets?.[0]?.amount + + const stableswapOut = stableswapEvents.find( + ({ args }) => args.poolId === assetOut, + ) + const stableswapAssetOut = stableswapOut?.args?.amounts?.[0]?.assetId + const stableswapAmountOut = stableswapIn?.args?.amounts?.[0]?.amount + event = { ...firstEvent, + args: { who: firstEvent.args.who, - assetIn: firstEvent.args.assetIn, - assetOut: lastEvent.args.assetOut, - amountIn: firstEvent.args.amount || firstEvent.args.amountIn, - amountOut: lastEvent.args.amount || lastEvent.args.amountOut, + assetIn: stableswapAssetIn || assetIn, + assetOut: stableswapAssetOut || assetOut, + amountIn: + stableswapAmountIn || + firstEvent.args.amount || + firstEvent.args.amountIn, + amountOut: + stableswapAmountOut || + lastEvent.args.amount || + lastEvent.args.amountOut, }, } } else { From b31b1beee9a3b7eacc6e1340d4fe2a8628ce9cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Fri, 10 May 2024 11:15:30 +0200 Subject: [PATCH 095/103] removed comments --- .../wallet/assets/paymentAsset/WalletPaymentAsset.tsx | 7 ------- .../web3-connect/wallets/MetaMask/MetaMaskSigner.ts | 7 +++---- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/sections/wallet/assets/paymentAsset/WalletPaymentAsset.tsx b/src/sections/wallet/assets/paymentAsset/WalletPaymentAsset.tsx index aa7a7a9c3..d4d0d856c 100644 --- a/src/sections/wallet/assets/paymentAsset/WalletPaymentAsset.tsx +++ b/src/sections/wallet/assets/paymentAsset/WalletPaymentAsset.tsx @@ -8,7 +8,6 @@ import { useRpcProvider } from "providers/rpcProvider" import { useTranslation } from "react-i18next" import { useEditFeePaymentAsset } from "sections/transaction/ReviewTransactionForm.utils" import { useAccount } from "sections/web3-connect/Web3Connect.utils" -import { isEvmAccount } from "utils/evm" export const WalletPaymentAsset = () => { const { t } = useTranslation() @@ -34,12 +33,6 @@ export const WalletPaymentAsset = () => { const isFeePaymentAssetEditable = acceptedFeePaymentAssetsIds.length > 1 - /* const isEvm = isEvmAccount(account?.address) - - if (isEvm) { - return null - } - */ return (
diff --git a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts index a6a727bd1..acee4bb6a 100644 --- a/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts +++ b/src/sections/web3-connect/wallets/MetaMask/MetaMaskSigner.ts @@ -4,6 +4,7 @@ import { Web3Provider, } from "@ethersproject/providers" import { evmChains } from "@galacticcouncil/xcm-sdk" +import BigNumber from "bignumber.js" import { Contract, Signature } from "ethers" import { splitSignature } from "ethers/lib/utils" import { @@ -59,16 +60,14 @@ export class MetaMaskSigner { }) } - getPermitNonce = async () => { + getPermitNonce = async (): Promise => { const callPermit = new Contract( CALL_PERMIT_ADDRESS, CALL_PERMIT_ABI, this.signer.provider, ) - const nonces = await callPermit.nonces(this.address) - - return nonces + return callPermit.nonces(this.address) } getPermit = async (data: string): Promise => { From 0faac85a7a1a7c08be02ccac243a821fecd33d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Fri, 10 May 2024 12:15:27 +0200 Subject: [PATCH 096/103] Fixed wallet asset trade button on mobile --- .../wallet/assets/table/actions/WalletAssetsTableActions.tsx | 2 +- .../wallet/assets/table/actions/WalletAssetsTableActionsMob.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx b/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx index a16b0db9d..e627433f2 100644 --- a/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx +++ b/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx @@ -103,7 +103,7 @@ export const WalletAssetsTableActions = (props: Props) => { onSelect: inTradeRouter ? () => navigate({ - to: "/trade/swap", + to: LINKS.swap, search: canBuy ? { assetOut: id } : { assetIn: id }, }) : undefined, diff --git a/src/sections/wallet/assets/table/actions/WalletAssetsTableActionsMob.tsx b/src/sections/wallet/assets/table/actions/WalletAssetsTableActionsMob.tsx index ad54dcedb..5f883202f 100644 --- a/src/sections/wallet/assets/table/actions/WalletAssetsTableActionsMob.tsx +++ b/src/sections/wallet/assets/table/actions/WalletAssetsTableActionsMob.tsx @@ -190,7 +190,7 @@ export const WalletAssetsTableActionsMob = ({ ) : (
Date: Fri, 10 May 2024 12:38:36 +0200 Subject: [PATCH 097/103] Force rerender OTC asset column on filter change --- .../trade/sections/otc/orders/OtcOrders.utils.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sections/trade/sections/otc/orders/OtcOrders.utils.tsx b/src/sections/trade/sections/otc/orders/OtcOrders.utils.tsx index 05f716979..754ff10b8 100644 --- a/src/sections/trade/sections/otc/orders/OtcOrders.utils.tsx +++ b/src/sections/trade/sections/otc/orders/OtcOrders.utils.tsx @@ -77,13 +77,20 @@ export const useOrdersTable = ( id: "offer", enableSorting: false, header: t("otc.offers.table.header.offer"), - cell: ({ row }) => , + cell: ({ row }) => ( + + ), }), accessor("accepting", { id: "accepting", enableSorting: false, header: t("otc.offers.table.header.accepting"), - cell: ({ row }) => , + cell: ({ row }) => ( + + ), }), accessor("orderPrice", { id: "orderPrice", From 3ab6dd0e5e3b8b33bde20f84a9aba2f6847e931c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Fri, 10 May 2024 14:16:19 +0200 Subject: [PATCH 098/103] Prevent info tooltip button from submitting forms --- src/components/InfoTooltip/InfoTooltip.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/InfoTooltip/InfoTooltip.tsx b/src/components/InfoTooltip/InfoTooltip.tsx index 59564c10d..d50457724 100644 --- a/src/components/InfoTooltip/InfoTooltip.tsx +++ b/src/components/InfoTooltip/InfoTooltip.tsx @@ -39,6 +39,7 @@ export function InfoTooltip({ }} > { textOnClick && e.preventDefault() From d6c8edab3df539c626c1027f505666ec008c12f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Mon, 13 May 2024 13:03:32 +0200 Subject: [PATCH 099/103] Fix stableswap trades --- src/api/volume.ts | 22 ++++++++++--------- .../data/RecentTradesTableData.utils.ts | 21 +++++++++++++----- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/api/volume.ts b/src/api/volume.ts index 460862819..85707c57c 100644 --- a/src/api/volume.ts +++ b/src/api/volume.ts @@ -196,17 +196,19 @@ export const getAllTrades = query TradeVolume($assetId: Int, $after: DateTime!) { events( where: { - name_in: [ - "Omnipool.SellExecuted" - "Omnipool.BuyExecuted" - "XYK.SellExecuted" - "XYK.BuyExecuted" - "Router.Executed" - ] - args_jsonContains: { assetIn: $assetId } - phase_eq: "ApplyExtrinsic" - block: { timestamp_gte: $after } OR: [ + { + name_in: [ + "Omnipool.SellExecuted" + "Omnipool.BuyExecuted" + "XYK.SellExecuted" + "XYK.BuyExecuted" + "Router.Executed" + ] + args_jsonContains: { assetIn: $assetId } + phase_eq: "ApplyExtrinsic" + block: { timestamp_gte: $after } + } { name_in: [ "Omnipool.SellExecuted" diff --git a/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts b/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts index a1dd60cf2..340a28f08 100644 --- a/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts +++ b/src/sections/stats/components/RecentTradesTable/data/RecentTradesTableData.utils.ts @@ -41,14 +41,27 @@ export const useRecentTradesTableData = (assetId?: string) => { return Object.entries(groupedEvents) .map(([, value]) => { - // check if last event is Router event const routerEvent = value.find(({ name }) => name === "Router.Executed") const tradeEvents = value.filter(isTradeEvent) const stableswapEvents = value.filter(isStableswapEvent) const [firstEvent] = tradeEvents if (!tradeEvents.length) return null - if (firstEvent?.name === "Router.Executed") return null + if (firstEvent?.name === "Router.Executed") { + const who = stableswapEvents?.[0]?.args?.who + if (!who) return null + return { + value, + ...firstEvent, + args: { + who: stableswapEvents[0].args.who, + assetIn: firstEvent.args.assetIn, + assetOut: firstEvent.args.assetOut, + amountIn: firstEvent.args.amountIn, + amountOut: firstEvent.args.amountOut, + }, + } + } let event: TradeType if (!routerEvent) { @@ -70,7 +83,6 @@ export const useRecentTradesTableData = (assetId?: string) => { event = { ...firstEvent, - args: { who: firstEvent.args.who, assetIn: stableswapAssetIn || assetIn, @@ -103,7 +115,6 @@ export const useRecentTradesTableData = (assetId?: string) => { return event }) .filter(isNotNil) - .slice(0, EVENTS_LIMIT) }, [allTrades.data, assets]) const assetIds = events @@ -211,7 +222,7 @@ export const useRecentTradesTableData = (assetId?: string) => { }>, ) - return trades + return trades.slice(0, EVENTS_LIMIT) }, [events, apiIds.data, spotPrices, assetId, assets, identities]) return { data, isLoading: isInitialLoading } From 5bcee12e5681263e854c9e875abc356b77831712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Mon, 13 May 2024 15:44:58 +0200 Subject: [PATCH 100/103] lintfix --- src/sections/transaction/ReviewTransaction.utils.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sections/transaction/ReviewTransaction.utils.tsx b/src/sections/transaction/ReviewTransaction.utils.tsx index bfe46927d..e76f5ba0d 100644 --- a/src/sections/transaction/ReviewTransaction.utils.tsx +++ b/src/sections/transaction/ReviewTransaction.utils.tsx @@ -15,7 +15,7 @@ import { useRef, useState } from "react" import { useTranslation } from "react-i18next" import { useMountedState } from "react-use" import { useEvmAccount } from "sections/web3-connect/Web3Connect.utils" -import { PermitResult } from "sections/web3-connect/wallets/MetaMask/MetaMaskSigner" +import { PermitResult } from "sections/web3-connect/signer/EthereumSigner" import { useToast } from "state/toasts" import { H160, getEvmChainById, getEvmTxLink, isEvmAccount } from "utils/evm" import { getSubscanLinkByType } from "utils/formatting" From 2ba5d4d0ea224a0ee543245b60f662da8c75a134 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Mon, 13 May 2024 15:59:16 +0200 Subject: [PATCH 101/103] Fix min deposit validation --- src/api/farms.ts | 1 + .../pools/farms/modals/join/JoinFarmsModal.utils.ts | 11 +++++++++-- src/utils/queryKeys.ts | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/api/farms.ts b/src/api/farms.ts index 05412a79a..c4dc61c02 100644 --- a/src/api/farms.ts +++ b/src/api/farms.ts @@ -476,6 +476,7 @@ const getOraclePrice = return { id: { rewardCurrency, incentivizedAsset }, oraclePrice: BN(oraclePrice), + price: { n, d }, } } diff --git a/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts b/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts index 905bc440e..8fbd4a8f5 100644 --- a/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts +++ b/src/sections/pools/farms/modals/join/JoinFarmsModal.utils.ts @@ -4,7 +4,7 @@ import { useTokenBalance } from "api/balances" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { useRpcProvider } from "providers/rpcProvider" import { BN_0 } from "utils/constants" -import { Farm } from "api/farms" +import { Farm, useOraclePrice } from "api/farms" import { useMemo } from "react" import { scale, scaleHuman } from "utils/balance" import { useTranslation } from "react-i18next" @@ -18,6 +18,7 @@ export const useZodSchema = ( const { account } = useAccount() const { assets } = useRpcProvider() const { data: balance } = useTokenBalance(id, account?.address) + const oraclePrice = useOraclePrice(assets.hub.id, id) const meta = assets.getAsset(id) @@ -32,7 +33,13 @@ export const useZodSchema = ( if (!balance) return undefined const rule = required.refine( - (value) => scale(value, meta.decimals).gte(minDeposit), + (value) => { + const valueInHub = scale(value, meta.decimals) + .times(oraclePrice.data?.price?.n ?? 1) + .div(oraclePrice.data?.price?.d ?? 1) + + return valueInHub.gte(minDeposit) + }, t("farms.modal.join.minDeposit", { value: scaleHuman(minDeposit, meta.decimals), }), diff --git a/src/utils/queryKeys.ts b/src/utils/queryKeys.ts index 6f87a39cb..f24c02c4d 100644 --- a/src/utils/queryKeys.ts +++ b/src/utils/queryKeys.ts @@ -82,7 +82,7 @@ export const QUERY_KEYS = { "activeYieldFarmsXYK", poolId?.toString(), ], - globalFarm: (id: string) => [QUERY_KEY_PREFIX, "globalFarm", id.toString], + globalFarm: (id: string) => [QUERY_KEY_PREFIX, "globalFarm", id], globalFarmXYK: (id: string) => [QUERY_KEY_PREFIX, "globalFarmXYK", id], yieldFarm: (id: string) => [QUERY_KEY_PREFIX, "yieldFarm", id], yieldFarmXYK: (id: string) => [QUERY_KEY_PREFIX, "yieldFarmXYK", id], From ab697f65876db7bd4954fae800f7668d9191f9d2 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Mon, 13 May 2024 16:06:49 +0200 Subject: [PATCH 102/103] Address MR comments --- src/sections/pools/sections/AllPools.tsx | 32 +++++++++++-------- src/sections/pools/sections/IsolatedPools.tsx | 32 +++++++++++-------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/sections/pools/sections/AllPools.tsx b/src/sections/pools/sections/AllPools.tsx index 5c449e03c..dd05d84db 100644 --- a/src/sections/pools/sections/AllPools.tsx +++ b/src/sections/pools/sections/AllPools.tsx @@ -120,10 +120,23 @@ const AllPoolsData = () => { ? arraySearch(pools.data, search, ["symbol", "name"]) : pools.data) ?? [] - const filteredXYKPools = - (search && xylPools.data - ? arraySearch(xylPools.data, search, ["symbol", "name"]) - : xylPools.data) ?? [] + const filteredXYKPools = useMemo( + () => + (search && xylPools.data + ? arraySearch(xylPools.data, search, ["symbol", "name"]) + : xylPools.data) ?? [], + [search, xylPools.data], + ) + + const visibleXykPools = useMemo( + () => + showAllXyk + ? filteredXYKPools + : filteredXYKPools.filter((pool) => + pool.tvlDisplay.gte(XYK_TVL_VISIBILITY), + ), + [filteredXYKPools, showAllXyk], + ) if (id != null) { const pool = [...(pools.data ?? []), ...(xylPools.data ?? [])].find( @@ -224,16 +237,7 @@ const AllPoolsData = () => { {xylPools.isInitialLoading ? ( ) : ( - - pool.tvlDisplay.gte(XYK_TVL_VISIBILITY), - ) - } - isXyk - /> + )}
) : null} diff --git a/src/sections/pools/sections/IsolatedPools.tsx b/src/sections/pools/sections/IsolatedPools.tsx index ba43efc5f..7e92b5cf5 100644 --- a/src/sections/pools/sections/IsolatedPools.tsx +++ b/src/sections/pools/sections/IsolatedPools.tsx @@ -78,10 +78,23 @@ const IsolatedPoolsData = () => { return BN_0 }, [xykPools.data]) - const filteredPools = - (search && xykPools.data - ? arraySearch(xykPools.data, search, ["symbol", "name"]) - : xykPools.data) ?? [] + const filteredPools = useMemo( + () => + (search && xykPools.data + ? arraySearch(xykPools.data, search, ["symbol", "name"]) + : xykPools.data) ?? [], + [search, xykPools.data], + ) + + const visiblePools = useMemo( + () => + showAllXyk + ? filteredPools + : filteredPools.filter((pool) => + pool.tvlDisplay.gte(XYK_TVL_VISIBILITY), + ), + [filteredPools, showAllXyk], + ) if (id != null) { const pool = xykPools.data?.find((pool) => pool.id === id.toString()) @@ -135,16 +148,7 @@ const IsolatedPoolsData = () => { {xykPools.isInitialLoading ? ( ) : filteredPools.length ? ( - - pool.tvlDisplay.gte(XYK_TVL_VISIBILITY), - ) - } - isXyk - /> + ) : ( )} From e311bbcade578af65d7ae60b6638c0f461558958 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Mon, 13 May 2024 17:40:21 +0200 Subject: [PATCH 103/103] fix mobile styling --- src/components/Switch/Switch.tsx | 2 +- src/sections/pools/sections/AllPools.tsx | 12 +++++++++++- src/sections/pools/sections/IsolatedPools.tsx | 10 +++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/components/Switch/Switch.tsx b/src/components/Switch/Switch.tsx index d4deee732..fb5300ee1 100644 --- a/src/components/Switch/Switch.tsx +++ b/src/components/Switch/Switch.tsx @@ -42,7 +42,7 @@ export const Switch = ({ label={label ?? ""} withLabel={!!label} sx={{ fontSize: fs, flex: "row", align: "center" }} - css={getLabelPositionCss(labelPosition)} + css={{ ...getLabelPositionCss(labelPosition), whiteSpace: "nowrap" }} className={className} > { align: ["flex-start", "flex-end"], }} > -
+
{ /> -
+
setShowAllXyk(value)}