Skip to content

Commit

Permalink
Update validate max transfer for substrate account
Browse files Browse the repository at this point in the history
  • Loading branch information
Thiendekaco committed Feb 29, 2024
1 parent 4d5ead6 commit 8d5f33d
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 69 deletions.
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
14 changes: 4 additions & 10 deletions packages/core/src/views/connect/ConnectingWallet.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
$: uri = '';
uriConnect$.subscribe((_uri)=>{
uri = _uri
uri = _uri;
setTimeout(()=> {
openQrModal();
}, 500)
})
qrModalConnect$.subscribe( async ({ isOpen, modal })=>{
Expand Down Expand Up @@ -188,14 +191,6 @@
</div>
{/if}
</div>
{#if (uri !== '')}
<div class="flex justify-between open-modal-footer absolute">
<div class="subtext footer-text">
Need the official WalletConnect modal?
</div>
<button on:click={openQrModal} class="button-open-modal onboard-button-primary " >Open</button>
</div>
{:else}
<button
on:click={() => {
deselectWallet(selectedWallet.label)
Expand All @@ -206,5 +201,4 @@
default: en.connect.connectingWallet.primaryButton
})}</button
>
{/if}
</div>
57 changes: 29 additions & 28 deletions packages/demo/src/components/account/AccountList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => <GeneralEmptyList />, []);
const [ accountsMap, setAccountMap ] = useState<AccountMapType[]>([])
Expand Down Expand Up @@ -84,25 +81,23 @@ 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])



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 = (
<div className={'__account-item-middle'}>
<div className={'__account-item-info'}>
Expand All @@ -111,20 +106,20 @@ function Component ({className, substrateProvider, evmProvider, setAddressToTran
</div>
<div className={'__account-item-info'}>
<span className='__account-item__title'>Address:</span>
<span className='__account-item__content'>{account}</span>
<span className='__account-item__content'>{address}</span>
</div>
<div className={'__account-item-info'}>
<Button
className={CN('__wallet-btn', '__sub-wallet-sign-btn')}
onClick={onSignClicked(account)}
onClick={onSignClicked(address)}
block={true}
>
Sign Dummy
</Button>

<Button
className={CN('__wallet-btn', '__sub-wallet-transaction-btn')}
onClick={onTransactionClicked(account)}
onClick={onTransactionClicked(address)}
block={true}
>
Transaction
Expand All @@ -133,25 +128,31 @@ function Component ({className, substrateProvider, evmProvider, setAddressToTran
</div>
)

const account = wallet?.accounts.find(({address: address_}) => address === address_)

return(
<Web3Block
key={key}
className={'__account-item'}
middleItem={_middleItem}
/>
<>
<Web3Block
key={key}
className={'__account-item'}
middleItem={_middleItem}
/>
{account && <TransactionModal senderAccount={account}
substrateProvider={substrateProvider}
evmProvider={evmProvider}/>}
</>

)
}, [wallet?.accounts, onSignClicked, onTransactionClicked])


return (
<SwList
className={CN('__account-list', className)}
list={accountsMap}
renderWhenEmpty={renderEmpty}
renderItem={accountItem}
/>

<SwList
className={CN('__account-list', className)}
list={accountsMap}
renderWhenEmpty={renderEmpty}
renderItem={accountItem}
/>
);
}

Expand Down
34 changes: 23 additions & 11 deletions packages/demo/src/components/transaction/TransactionModal.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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";

Expand All @@ -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<TransferParams>({
Expand Down Expand Up @@ -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<void> => {
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();
}, []);
Expand Down Expand Up @@ -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+)?$/));
Expand Down
12 changes: 1 addition & 11 deletions packages/demo/src/pages/EvmWalletInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -33,7 +27,6 @@ function Component ({className}: Props): React.ReactElement {
const [{ chains}, setChain] = useSetChain();
const navigate = useNavigate();
const [ evmProvider, setEvmProvider ] = useState<evmApi>();
const [ currentAccountToTransaction, setCurrentAccountToTransaction ] = useState<Account>();
const customNotification = useNotifications()[1];
const { isWebUI } = useContext(ScreenContext);

Expand Down Expand Up @@ -81,7 +74,7 @@ function Component ({className}: Props): React.ReactElement {
<div className={'__evm-wallet-info-label'}>
Account List
</div>
<AccountList evmProvider={evmProvider} setAddressToTransaction={setCurrentAccountToTransaction}/>
<AccountList evmProvider={evmProvider}/>
</div>
<div className={'__evm-wallet-info-box'}>
<div className={'__evm-wallet-info-label'}>Permission</div>
Expand All @@ -100,9 +93,6 @@ function Component ({className}: Props): React.ReactElement {
</div>
</div>
</div>
{
currentAccountToTransaction && <TransactionModal senderAccount={currentAccountToTransaction} evmProvider={evmProvider}/>
}
</div>
);
}
Expand Down
9 changes: 1 addition & 8 deletions packages/demo/src/pages/WalletInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";


Expand All @@ -25,7 +22,6 @@ function Component ({className}: Props): React.ReactElement {
const navigate = useNavigate();
const [ { wallet}] = useConnectWallet();
const [ substrateProvider, setSubstrateProvider ] = useState<substrateApi>();
const [ currentAccountToTransaction, setCurrentAccountToTransaction ] = useState<Account>();
const [{ chains }] = useSetChain();
const { isWebUI } = useContext(ScreenContext);

Expand All @@ -51,7 +47,7 @@ function Component ({className}: Props): React.ReactElement {
<div className={'__wallet-info-label'}>
Account List
</div>
<AccountList substrateProvider={substrateProvider} setAddressToTransaction={setCurrentAccountToTransaction}/>
<AccountList substrateProvider={substrateProvider}/>
</div>
<div className={'__wallet-info-box'}>
{!! wallet?.metadata &&
Expand All @@ -64,9 +60,6 @@ function Component ({className}: Props): React.ReactElement {
}
</div>
</div>
{
currentAccountToTransaction && <TransactionModal senderAccount={currentAccountToTransaction} substrateProvider={substrateProvider}/>
}
</div>
);
}
Expand Down
12 changes: 12 additions & 0 deletions packages/demo/src/utils/api/substrateApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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());
Expand Down

0 comments on commit 8d5f33d

Please sign in to comment.