From 8d5f33deb890d5136edd7d9331e1aecd865bb698 Mon Sep 17 00:00:00 2001 From: Thiendekaco Date: Thu, 29 Feb 2024 08:58:39 +0700 Subject: [PATCH] Update validate max transfer for substrate account --- packages/core/package.json | 2 +- .../src/views/connect/ConnectingWallet.svelte | 14 ++--- .../src/components/account/AccountList.tsx | 57 ++++++++++--------- .../transaction/TransactionModal.tsx | 34 +++++++---- packages/demo/src/pages/EvmWalletInfo.tsx | 12 +--- packages/demo/src/pages/WalletInfo.tsx | 9 +-- packages/demo/src/utils/api/substrateApi.ts | 12 ++++ 7 files changed, 71 insertions(+), 69 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index 70f78ac72..64ada5254 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -89,7 +89,7 @@ "@subwallet_connect/common": "^1.0.2", "axios": "^1.6.5", "bignumber.js": "^9.0.0", - "bn.js": "^5.2.1", + "bn.js": "^4.11.9", "bnc-sdk": "^4.6.7", "bowser": "^2.11.0", "ethers": "5.5.3", diff --git a/packages/core/src/views/connect/ConnectingWallet.svelte b/packages/core/src/views/connect/ConnectingWallet.svelte index 573398665..c2a39f5e7 100644 --- a/packages/core/src/views/connect/ConnectingWallet.svelte +++ b/packages/core/src/views/connect/ConnectingWallet.svelte @@ -22,7 +22,10 @@ $: uri = ''; uriConnect$.subscribe((_uri)=>{ - uri = _uri + uri = _uri; + setTimeout(()=> { + openQrModal(); + }, 500) }) qrModalConnect$.subscribe( async ({ isOpen, modal })=>{ @@ -188,14 +191,6 @@ {/if} - {#if (uri !== '')} - - {:else} - {/if} diff --git a/packages/demo/src/components/account/AccountList.tsx b/packages/demo/src/components/account/AccountList.tsx index aafb50755..683a7a669 100644 --- a/packages/demo/src/components/account/AccountList.tsx +++ b/packages/demo/src/components/account/AccountList.tsx @@ -11,32 +11,29 @@ import { SubstrateProvider } from "@subwallet_connect/common"; import { GeneralEmptyList } from "../empty"; import { ThemeProps } from "../../types"; import CN from "classnames"; -import styled from "styled-components"; import { evmApi } from "../../utils/api/evmApi"; import { substrateApi } from "../../utils/api/substrateApi"; -import { NetworkInfo } from "../../utils/network"; -import {TRANSACTION_MODAL} from "../../constants/modal"; import {toShort} from "../../utils/style"; +import TransactionModal from "../transaction/TransactionModal"; +import styled from "styled-components"; interface Props extends ThemeProps{ substrateProvider ?: substrateApi, evmProvider ?: evmApi, - setAddressToTransaction : (account?: Account) => void; }; type AccountMapType = { - account: string, + address: string, name: string, index: number } -const modalId = TRANSACTION_MODAL; -function Component ({className, substrateProvider, evmProvider, setAddressToTransaction}: Props): React.ReactElement { +function Component ({className, substrateProvider, evmProvider}: Props): React.ReactElement { const [{ wallet},] = useConnectWallet(); const renderEmpty = useCallback(() => , []); const [ accountsMap, setAccountMap ] = useState([]) @@ -84,9 +81,7 @@ function Component ({className, substrateProvider, evmProvider, setAddressToTran const onTransactionClicked = useCallback( (address_: string) => { return async () => { - const account = wallet?.accounts.find(({address}) => address === address_) - setAddressToTransaction(account); - activeModal(modalId); + activeModal(`${address_}`); }; }, [wallet]) @@ -94,15 +89,15 @@ function Component ({className, substrateProvider, evmProvider, setAddressToTran useEffect(() => { const accountMap = wallet?.accounts.reduce((acc, account, index)=>{ - acc.push({account: account.address, index, name: account.uns?.name || account.ens?.name || toShort(account.address)}) + acc.push({address: account.address, index, name: account.uns?.name || account.ens?.name || toShort(account.address)}) return acc }, [] as AccountMapType[]) setAccountMap(accountMap || []); }, [wallet?.accounts]); - const accountItem = useCallback(({ account, name }: AccountMapType) => { - const key = `${account}_${name}` + const accountItem = useCallback(({ address, name }: AccountMapType) => { + const key = `${address}_${name}` const _middleItem = (
@@ -111,12 +106,12 @@ function Component ({className, substrateProvider, evmProvider, setAddressToTran
Address: - {account} + {address}
) + const account = wallet?.accounts.find(({address: address_}) => address === address_) return( - + <> + + {account && } + + ) }, [wallet?.accounts, onSignClicked, onTransactionClicked]) return ( - - + ); } diff --git a/packages/demo/src/components/transaction/TransactionModal.tsx b/packages/demo/src/components/transaction/TransactionModal.tsx index 58a8b30f4..4051e75e2 100644 --- a/packages/demo/src/components/transaction/TransactionModal.tsx +++ b/packages/demo/src/components/transaction/TransactionModal.tsx @@ -1,9 +1,9 @@ import { ThemeProps, TransferParams, FormCallbacks, Theme } from "../../types"; import {TRANSACTION_MODAL} from "../../constants/modal"; -import {BaseModal} from "../modal"; -import {Button, Form, Icon, Input, ModalContext} from '@subwallet/react-ui'; -import {useState, useCallback, useMemo, useEffect, useContext} from "react"; -import {useConnectWallet, useNotifications, useSetChain} from "@subwallet_connect/react"; +import { BaseModal} from "../modal"; +import { Button, Form, Icon, Input, ModalContext } from '@subwallet/react-ui'; +import { useState, useCallback, useMemo, useEffect, useContext } from "react"; +import { useConnectWallet, useNotifications, useSetChain } from "@subwallet_connect/react"; import { Rule } from '@subwallet/react-ui/es/form'; import { useWatchTransaction } from "../../hooks"; import styled from 'styled-components'; @@ -13,8 +13,8 @@ import CN from "classnames"; import AccountBriefInfo from "../account/AccountBriefInfo"; import type { Account } from '@subwallet_connect/core/dist/types'; import { PaperPlaneTilt } from "@phosphor-icons/react"; -import {NetworkInfo} from "../../utils/network"; -import { SubstrateProvider } from "@subwallet_connect/common"; +import { NetworkInfo } from "../../utils/network"; +import {EIP1193Provider, SubstrateProvider} from "@subwallet_connect/common"; import { substrateApi } from "../../utils/api/substrateApi"; import { evmApi } from "../../utils/api/evmApi"; @@ -24,13 +24,12 @@ export interface Props extends ThemeProps { evmProvider ?: evmApi, }; -const modalId = TRANSACTION_MODAL; - function Component ({ className, senderAccount, evmProvider, substrateProvider }: Props) { const [{ wallet},] = useConnectWallet(); const [{ chains }] = useSetChain(); + const modalId = useMemo(() => `${senderAccount.address}`, [senderAccount.address, wallet]) const [loading, setLoading] = useState(false); const [, customNotification, updateNotify,] = useNotifications(); const [ defaultData, persistData ] = useState({ @@ -67,17 +66,30 @@ function Component ({ className, senderAccount, evmProvider, substrateProvider } return Promise.reject('Invalid recipient address'); } + if((wallet?.type === 'evm' && !isEthereumAddress(_recipientAddress)) + || (wallet?.type === 'substrate' && isEthereumAddress(_recipientAddress))){ + return Promise.reject('Invalid recipient address type'); + } + if(_recipientAddress === senderAccount.address) { + return Promise.reject('The receiving address and sending address must be different') + } return Promise.resolve(); - }, [form]); + }, [form, wallet, senderAccount]); const validateAmount = useCallback((rule: Rule, amount: string): Promise => { - if (!amount) { + if (!amount || !amount.trim()) { return Promise.reject('Amount is required'); } + if ((new BigN(amount)).eq(new BigN(0))) { + return Promise.reject('Amount must be greater than 0'); + } + if(!isValidInput(amount)){ + return Promise.reject('Amount is invalid') + } return Promise.resolve(); }, []); @@ -144,7 +156,7 @@ function Component ({ className, senderAccount, evmProvider, substrateProvider } setLoading(false) blockHash !== '' && onCloseModal(); }catch (e) {} - }, [wallet, chains, senderAccount ]); + }, [wallet, chains, senderAccount, evmProvider, substrateProvider ]); const isValidInput = useCallback((input: string) => { return !(isNaN(parseFloat(input)) || !input.match(/^-?\d*(\.\d+)?$/)); diff --git a/packages/demo/src/pages/EvmWalletInfo.tsx b/packages/demo/src/pages/EvmWalletInfo.tsx index a2a027fcd..c5e807509 100644 --- a/packages/demo/src/pages/EvmWalletInfo.tsx +++ b/packages/demo/src/pages/EvmWalletInfo.tsx @@ -5,20 +5,14 @@ import React, { useCallback, useContext, useEffect, useState } from 'react'; import {useConnectWallet, useNotifications, useSetChain} from "@subwallet_connect/react"; import {useNavigate} from "react-router-dom"; -import {HeaderWalletInfo} from "../components/header/HeaderWalletInfo"; import { ThemeProps } from '../types'; import CN from "classnames"; import styled from "styled-components"; import AccountList from "../components/account/AccountList"; -import WalletMetadata from "../components/sub_action/metadata/WalletMetadata"; import {PlusCircleOutlined} from "@ant-design/icons"; import {Button, Web3Block} from "@subwallet/react-ui"; import {EIP1193Provider} from "@subwallet_connect/common"; -import {METHOD_MAP} from "../utils/methods"; import {evmApi} from "../utils/api/evmApi"; -import {NetworkInfo} from "../utils/network"; -import {substrateApi} from "../utils/api/substrateApi"; -import TransactionModal from "../components/transaction/TransactionModal"; import type { Account } from '@subwallet_connect/core/dist/types'; import {ScreenContext} from "../context/ScreenContext"; @@ -33,7 +27,6 @@ function Component ({className}: Props): React.ReactElement { const [{ chains}, setChain] = useSetChain(); const navigate = useNavigate(); const [ evmProvider, setEvmProvider ] = useState(); - const [ currentAccountToTransaction, setCurrentAccountToTransaction ] = useState(); const customNotification = useNotifications()[1]; const { isWebUI } = useContext(ScreenContext); @@ -81,7 +74,7 @@ function Component ({className}: Props): React.ReactElement {
Account List
- +
Permission
@@ -100,9 +93,6 @@ function Component ({className}: Props): React.ReactElement {
- { - currentAccountToTransaction && - } ); } diff --git a/packages/demo/src/pages/WalletInfo.tsx b/packages/demo/src/pages/WalletInfo.tsx index b1c24eae4..7562ef481 100644 --- a/packages/demo/src/pages/WalletInfo.tsx +++ b/packages/demo/src/pages/WalletInfo.tsx @@ -7,14 +7,11 @@ import AccountList from '../components/account/AccountList'; import WalletMetadata from '../components/sub_action/metadata/WalletMetadata'; import { useNavigate } from "react-router-dom"; import {useConnectWallet, useSetChain} from "@subwallet_connect/react"; -import { HeaderWalletInfo } from "../components/header/HeaderWalletInfo"; import styled from "styled-components"; import {ThemeProps} from "../types"; import CN from "classnames"; import {NetworkInfo} from "../utils/network"; import {substrateApi} from "../utils/api/substrateApi"; -import {Account} from "@subwallet_connect/core/dist/types"; -import TransactionModal from "../components/transaction/TransactionModal"; import {ScreenContext} from "../context/ScreenContext"; @@ -25,7 +22,6 @@ function Component ({className}: Props): React.ReactElement { const navigate = useNavigate(); const [ { wallet}] = useConnectWallet(); const [ substrateProvider, setSubstrateProvider ] = useState(); - const [ currentAccountToTransaction, setCurrentAccountToTransaction ] = useState(); const [{ chains }] = useSetChain(); const { isWebUI } = useContext(ScreenContext); @@ -51,7 +47,7 @@ function Component ({className}: Props): React.ReactElement {
Account List
- +
{!! wallet?.metadata && @@ -64,9 +60,6 @@ function Component ({className}: Props): React.ReactElement { }
- { - currentAccountToTransaction && - } ); } diff --git a/packages/demo/src/utils/api/substrateApi.ts b/packages/demo/src/utils/api/substrateApi.ts index 116823c7e..688fa090f 100644 --- a/packages/demo/src/utils/api/substrateApi.ts +++ b/packages/demo/src/utils/api/substrateApi.ts @@ -6,6 +6,8 @@ import { RequestArguments } from "../../types"; import { SIGN_METHODS } from "../methods"; import { LedgerSignature } from "@polkadot/hw-ledger/types"; import { blake2AsU8a } from '@polkadot/util-crypto'; +import { BN_HUNDRED, BN_ZERO, isFunction, nextTick } from '@polkadot/util'; +import BN from 'bn.js'; export class substrateApi { private readonly api ?: ApiPromise; @@ -25,9 +27,19 @@ export class substrateApi { if(!this.api || !this.api.isReady || !signer) return; const transferExtrinsic = this.api.tx.balances.transferKeepAlive(recipientAddress, amount) + const [ { partialFee }, balances ] = await Promise.all([ + transferExtrinsic.paymentInfo(senderAddress), + this.api.derive.balances?.all(senderAddress) + ]) + const adjFee = partialFee.muln(110).div(BN_HUNDRED); + const maxTransfer = balances.availableBalance.sub(adjFee); + console.log(maxTransfer.toString()) try{ const sendTransaction = async (fn: (hash: string) => void) => { let txHash_ = '' + if(!maxTransfer.gt(new BN(this.api?.consts.balances.existentialDeposit as any))){ + throw new Error ('The account does not have enough free funds available to cover the transaction fees without dropping the balance below the account existential amount.') + } await transferExtrinsic.signAndSend(senderAddress, { signer }, ({ status, txHash }) => { if (status.isInBlock) { fn(txHash.toString());