Show minimum balance on asset mint/transfer (#5134)

* Show minimum blanace on asset mint/transfer

* Bump API
This commit is contained in:
Jaco 2021-04-24 08:08:50 +03:00 committed by GitHub
parent 082a270dd0
commit d00c562e70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 66 additions and 59 deletions

View File

@ -12,13 +12,13 @@
"packages/*"
],
"resolutions": {
"@polkadot/api": "^4.6.3-9",
"@polkadot/api-contract": "^4.6.3-9",
"@polkadot/api": "^4.6.3-10",
"@polkadot/api-contract": "^4.6.3-10",
"@polkadot/hw-ledger": "^6.2.2-7",
"@polkadot/keyring": "^6.2.2-7",
"@polkadot/networks": "^6.2.2-7",
"@polkadot/phishing": "^0.6.104",
"@polkadot/types": "^4.6.3-9",
"@polkadot/types": "^4.6.3-10",
"@polkadot/util": "^6.2.2-7",
"@polkadot/util-crypto": "^6.2.2-7",
"@polkadot/wasm-crypto": "^4.0.2",

View File

@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/app-assets authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { AssetBalance, AssetId } from '@polkadot/types/interfaces';
import type { AssetBalance, AssetId, TAssetBalance } from '@polkadot/types/interfaces';
import React from 'react';
@ -16,10 +16,11 @@ interface Props {
assetId: AssetId;
balance: AssetBalance;
className?: string;
minBalance: TAssetBalance;
siFormat: [number, string];
}
function Account ({ accountId, assetId, balance: { balance, isFrozen, isSufficient }, className, siFormat }: Props): React.ReactElement<Props> {
function Account ({ accountId, assetId, balance: { balance, isFrozen, isSufficient }, className, minBalance, siFormat }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
return (
@ -43,6 +44,7 @@ function Account ({ accountId, assetId, balance: { balance, isFrozen, isSufficie
<Transfer
accountId={accountId}
assetId={assetId}
minBalance={minBalance}
siFormat={siFormat}
/>
</td>

View File

@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
import type BN from 'bn.js';
import type { AssetId } from '@polkadot/types/interfaces';
import type { AssetId, TAssetBalance } from '@polkadot/types/interfaces';
import React, { useMemo, useState } from 'react';
import React, { useState } from 'react';
import { Button, InputAddress, InputBalance, Modal, Toggle, TxButton } from '@polkadot/react-components';
import { useApi, useToggle } from '@polkadot/react-hooks';
@ -15,10 +15,11 @@ interface Props {
accountId: string;
assetId: AssetId;
className?: string;
minBalance: TAssetBalance;
siFormat: [number, string];
}
function Transfer ({ accountId, assetId, className, siFormat: [siDecimals, siSymbol] }: Props): React.ReactElement<Props> {
function Transfer ({ accountId, assetId, className, minBalance, siFormat: [siDecimals, siSymbol] }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const [isOpen, toggleOpen] = useToggle();
@ -26,11 +27,6 @@ function Transfer ({ accountId, assetId, className, siFormat: [siDecimals, siSym
const [recipientId, setRecipientId] = useState<string | null>(null);
const [isProtected, setIsProtected] = useState(true);
const isAmountValid = useMemo(
() => !!amount && !amount.isZero(),
[amount]
);
return (
<>
<Button
@ -59,17 +55,24 @@ function Transfer ({ accountId, assetId, className, siFormat: [siDecimals, siSym
type='allPlus'
/>
</Modal.Columns>
<Modal.Columns hint={t<string>('The amount of tokens to issue to the account.')}>
<Modal.Columns hint={t<string>('The amount of tokens to transfer to the account.')}>
<InputBalance
autoFocus
isError={!isAmountValid}
isZeroable={false}
label={t<string>('amount to transfer')}
onChange={setAmount}
siDecimals={siDecimals}
siSymbol={siSymbol}
/>
</Modal.Columns>
<Modal.Columns hint={t<string>('The minimum balance allowed for the asset.')}>
<InputBalance
defaultValue={minBalance}
isDisabled
label={t<string>('minimum balance')}
siDecimals={siDecimals}
siSymbol={siSymbol}
/>
</Modal.Columns>
<Modal.Columns hint={t('With the keep-alive option set, the account is protected against removal due to low balances.')}>
<Toggle
className='typeToggle'
@ -87,7 +90,7 @@ function Transfer ({ accountId, assetId, className, siFormat: [siDecimals, siSym
<TxButton
accountId={accountId}
icon='paper-plane'
isDisabled={!recipientId || !isAmountValid}
isDisabled={!recipientId || !amount}
label={t<string>('Send')}
onStart={toggleOpen}
params={[assetId, recipientId, amount]}

View File

@ -85,6 +85,7 @@ function Balances ({ className, infos = [] }: Props): React.ReactElement<Props>
assetId={info.id}
balance={balance}
key={accountId}
minBalance={info.details.minBalance}
siFormat={siFormat}
/>
))}

View File

@ -3,48 +3,35 @@
import type { AssetBalance, AssetId } from '@polkadot/types/interfaces';
import { useEffect, useState } from 'react';
import { useAccounts, useApi, useCall } from '@polkadot/react-hooks';
import { useAccounts, useApi, useCall, useIsMountedRef } from '@polkadot/react-hooks';
interface Result {
interface BalanceResult {
accountId: string;
balance: AssetBalance;
}
interface Result {
assetId: AssetId;
balances: BalanceResult[];
}
const queryOptions = {
transform: ([[params], balances]: [[[AssetId, string][]], AssetBalance[]]): Result[] =>
params
transform: ([[params], balances]: [[[AssetId, string][]], AssetBalance[]]): Result => ({
assetId: params[0][0],
balances: params
.map(([, accountId], index) => ({
accountId,
balance: balances[index]
}))
.filter(({ balance: { balance } }) => !balance.isZero()),
.filter(({ balance: { balance } }) => !balance.isZero())
}),
withParamsTransform: true
};
export default function useBalances (id?: AssetId | null): Result[] | null {
export default function useBalances (id?: AssetId | null): BalanceResult[] | null {
const { api } = useApi();
const { allAccounts } = useAccounts();
const mountedRef = useIsMountedRef();
const [state, setState] = useState<Result[] | null>(null);
const query = useCall(id && api.query.assets.account.multi, [allAccounts.map((a) => [id, a])], queryOptions);
const query = useCall(id && api.query.assets.account.multi, id && [allAccounts.map((a) => [id, a])], queryOptions);
useEffect((): void => {
if (mountedRef.current) {
setState(null);
if (id) {
// dummy
}
}
}, [id, mountedRef]);
useEffect((): void => {
if (mountedRef.current && query) {
setState(query);
}
}, [query, mountedRef]);
return state;
return (query && id && (query.assetId === id) && query.balances) || null;
}

View File

@ -67,6 +67,15 @@ function Mint ({ className, details: { issuer, minBalance }, id, metadata, onClo
siSymbol={siSymbol}
/>
</Modal.Columns>
<Modal.Columns hint={t<string>('The minimum balance allowed for the asset.')}>
<InputBalance
defaultValue={minBalance}
isDisabled
label={t<string>('minimum balance')}
siDecimals={siDecimals}
siSymbol={siSymbol}
/>
</Modal.Columns>
</Modal.Content>
<Modal.Actions onCancel={onClose}>
<TxButton

View File

@ -5,6 +5,6 @@
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.13.17",
"@polkadot/api-contract": "^4.6.3-9"
"@polkadot/api-contract": "^4.6.3-10"
}
}

View File

@ -5,7 +5,7 @@
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.13.17",
"@polkadot/api": "^4.6.3-9",
"@polkadot/api": "^4.6.3-10",
"@polkadot/extension-dapp": "^0.37.3-16",
"@polkadot/x-rxjs": "^6.2.2-7",
"fflate": "^0.6.9"

View File

@ -8,7 +8,7 @@ import React, { useMemo } from 'react';
import styled from 'styled-components';
import { BitLengthOption } from '@polkadot/react-components/constants';
import { BN_TEN, formatBalance, isBn } from '@polkadot/util';
import { BN_TEN, formatBalance, isBn, isUndefined } from '@polkadot/util';
import InputNumber from './InputNumber';
@ -41,12 +41,16 @@ interface Props {
const BN_TEN_THOUSAND = new BN(10_000);
const DEFAULT_BITLENGTH = BitLengthOption.CHAIN_SPEC as BitLength;
function reformat (value: string | BN, isDisabled?: boolean): string {
function reformat (value: string | BN, isDisabled?: boolean, siDecimals?: number): string {
const decimals = isUndefined(siDecimals)
? formatBalance.getDefaults().decimals
: siDecimals;
if (isBn(value)) {
// format for 4 decimals (align with util)
const valStr = value
.mul(BN_TEN_THOUSAND)
.div(BN_TEN.pow(new BN(formatBalance.getDefaults().decimals)))
.div(BN_TEN.pow(new BN(decimals)))
.toString()
.padStart(5, '0'); // 4 after decimal, 1 before, min 5
@ -67,13 +71,13 @@ function reformat (value: string | BN, isDisabled?: boolean): string {
return fmt;
}
return formatBalance(value, { forceUnit: '-', withSi: false }).replace(',', isDisabled ? ',' : '');
return formatBalance(value, { decimals, forceUnit: '-', withSi: false }).replace(',', isDisabled ? ',' : '');
}
function InputBalance ({ autoFocus, children, className = '', defaultValue: inDefault, help, isDisabled, isError, isFull, isWarning, isZeroable, label, labelExtra, maxValue, onChange, onEnter, onEscape, placeholder, siDecimals, siSymbol, value, withEllipsis, withLabel, withMax }: Props): React.ReactElement<Props> {
const defaultValue = useMemo(
() => inDefault ? reformat(inDefault, isDisabled) : undefined,
[inDefault, isDisabled]
() => inDefault ? reformat(inDefault, isDisabled, siDecimals) : undefined,
[inDefault, isDisabled, siDecimals]
);
return (

View File

@ -137,7 +137,8 @@ export default React.memo(styled(Head)`
}
&.filter {
.ui.input {
.ui.input,
.ui.selection.dropdown {
background: transparent;
&:first-child {

View File

@ -2145,7 +2145,7 @@ __metadata:
languageName: node
linkType: hard
"@polkadot/api-contract@npm:^4.6.3-9":
"@polkadot/api-contract@npm:^4.6.3-10":
version: 4.6.3-10
resolution: "@polkadot/api-contract@npm:4.6.3-10"
dependencies:
@ -2175,7 +2175,7 @@ __metadata:
languageName: node
linkType: hard
"@polkadot/api@npm:^4.6.3-9":
"@polkadot/api@npm:^4.6.3-10":
version: 4.6.3-10
resolution: "@polkadot/api@npm:4.6.3-10"
dependencies:
@ -2265,7 +2265,7 @@ __metadata:
resolution: "@polkadot/app-contracts@workspace:packages/page-contracts"
dependencies:
"@babel/runtime": ^7.13.17
"@polkadot/api-contract": ^4.6.3-9
"@polkadot/api-contract": ^4.6.3-10
languageName: unknown
linkType: soft
@ -2725,7 +2725,7 @@ __metadata:
resolution: "@polkadot/react-api@workspace:packages/react-api"
dependencies:
"@babel/runtime": ^7.13.17
"@polkadot/api": ^4.6.3-9
"@polkadot/api": ^4.6.3-10
"@polkadot/extension-dapp": ^0.37.3-16
"@polkadot/x-rxjs": ^6.2.2-7
fflate: ^0.6.9
@ -2921,7 +2921,7 @@ __metadata:
languageName: node
linkType: hard
"@polkadot/types@npm:^4.6.3-9":
"@polkadot/types@npm:^4.6.3-10":
version: 4.6.3-10
resolution: "@polkadot/types@npm:4.6.3-10"
dependencies: