@polkadot/util#formatBalance TypeScript Examples
The following examples show how to use
@polkadot/util#formatBalance.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: InputCandyNumber.tsx From crust-apps with Apache License 2.0 | 6 votes |
function getSiPowers (si: SiDef | null): [BN, number, number] {
if (!si) {
return [BN_ZERO, 0, 0];
}
const basePower = formatBalance.getDefaults().decimals;
return [new BN(basePower + si.power), basePower, si.power];
}
Example #2
Source File: substrate.ts From subsocial-js with GNU General Public License v3.0 | 6 votes |
getSubstrateApi = async (nodeUrl?: string) => {
if (api) return api
const rpcEndpoint = nodeUrl || 'ws://127.0.0.1:9944/';
const provider = new WsProvider(rpcEndpoint);
logger.info(`Connecting to Substrate node at ${rpcEndpoint}...`);
api = new ApiPromise({ provider, typesBundle })
await api.isReady
const properties = await api.rpc.system.properties() as ChainProperties
const tokenSymbol = properties.tokenSymbol.unwrapOr(undefined)?.map((x: Text) => x.toString());
const tokenDecimals = properties.tokenDecimals.unwrapOr(undefined)?.map((x: U32) => x.toNumber());
registry.setChainProperties(properties)
formatBalance.setDefaults({
decimals: tokenDecimals,
unit: tokenSymbol
});
return api
}
Example #3
Source File: InputBalance.tsx From crust-apps with Apache License 2.0 | 6 votes |
function reformat (value: string | BN, isDisabled?: boolean): string {
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)))
.toString()
.padStart(5, '0'); // 4 after decimal, 1 before, min 5
// dive using string format (the value may be too large for 2^53-1)
let fmt = `${valStr.substr(0, valStr.length - 4)}.${valStr.slice(-4)}`;
// remove all trailing 0's until the decimal
while (fmt.length !== 1 && ['.', '0'].includes(fmt[fmt.length - 1])) {
const isLast = fmt.endsWith('.');
fmt = fmt.substr(0, fmt.length - 1);
if (isLast) {
break;
}
}
return fmt;
}
return formatBalance(value, { forceUnit: '-', withSi: false }).replace(',', isDisabled ? ',' : '');
}
Example #4
Source File: useBalance.ts From parity-bridges-ui with GNU General Public License v3.0 | 6 votes |
useBalance = (api: ApiPromise, address: string, providedSi: boolean = false): State => {
const [state, setState] = useMountedState<State>(initValues);
const { areApiReady } = useLoadingApi();
const getBalanceCall = useCallback(
() =>
api.query.system.account(address, ({ data }): void => {
setState({
chainTokens: data.registry.chainTokens[0],
formattedBalance: formatBalance(data.free, {
decimals: api.registry.chainDecimals[0],
withUnit: api.registry.chainTokens[0],
withSi: providedSi
}),
free: data.free
});
}),
[address, api, providedSi, setState]
);
useApiSubscription(getBalanceCall, areApiReady && Boolean(address));
return state as State;
}
Example #5
Source File: index.ts From sdk with Apache License 2.0 | 6 votes |
function _extractUnbondings(stakingInfo: any, progress: any) {
if (!stakingInfo?.unlocking || !progress) {
return { mapped: [], total: BN_ZERO };
}
const mapped = stakingInfo.unlocking
.filter(
({ remainingEras, value }) =>
value.gt(BN_ZERO) && remainingEras.gt(BN_ZERO)
)
.map((unlock: any) => [
unlock,
unlock.remainingEras
.sub(BN_ONE)
.imul(progress.eraLength)
.iadd(progress.eraLength)
.isub(progress.eraProgress)
.toNumber(),
]);
const total = mapped.reduce(
(total: BN, [{ value }]) => total.iadd(value),
new BN(0)
);
return {
mapped: mapped.map((i: any) => [
formatBalance(i[0].value, { forceUnit: "-", withSi: false }),
i[1],
]),
total,
};
}
Example #6
Source File: InputCandyNumber.tsx From crust-apps with Apache License 2.0 | 6 votes |
function getValuesFromBn (valueBn: BN, si: SiDef | null): [string, BN, boolean] {
const value = si
? valueBn.div(BN_TEN.pow(new BN(formatBalance.getDefaults().decimals + si.power))).toString()
: valueBn.toString();
return [
value,
valueBn,
true
];
}
Example #7
Source File: InputBalance.tsx From subscan-multisig-react with Apache License 2.0 | 6 votes |
function reformat(value?: string | BN, isDisabled?: boolean, siDecimals?: number): [string?, SiDef?] {
if (!value) {
return [];
}
const decimals = isUndefined(siDecimals) ? formatBalance.getDefaults().decimals : siDecimals;
const si = isDisabled ? formatBalance.calcSi(value.toString(), decimals) : formatBalance.findSi('-');
return [
formatBalance(value, { decimals, forceUnit: si.value, withSi: false }).replace(',', isDisabled ? ',' : ''),
si,
];
}
Example #8
Source File: InputCsmBalance.tsx From crust-apps with Apache License 2.0 | 6 votes |
function reformat (value: string | BN, isDisabled?: boolean): string {
if (isBn(value)) {
let fmt = (value.mul(BN_THOUSAND).div(BN_TEN.pow(new BN(formatBalance.getDefaults().decimals))).toNumber() / 1000).toFixed(3);
while (fmt.length !== 1 && ['.', '0'].includes(fmt[fmt.length - 1])) {
const isLast = fmt.endsWith('.');
fmt = fmt.substr(0, fmt.length - 1);
if (isLast) {
break;
}
}
return fmt;
}
return formatBalance(value, { forceUnit: '-', withSi: false }).replace(',', isDisabled ? ',' : '');
}
Example #9
Source File: InputNumber.tsx From subscan-multisig-react with Apache License 2.0 | 6 votes |
function getSiPowers(si: SiDef | null, decimals?: number): [BN, number, number] {
if (!si) {
return [BN_ZERO, 0, 0];
}
const basePower = isUndefined(decimals) ? formatBalance.getDefaults().decimals : decimals;
return [new BN(basePower + si.power), basePower, si.power];
}
Example #10
Source File: InputCsmNumber.tsx From crust-apps with Apache License 2.0 | 6 votes |
function getValuesFromBn (valueBn: BN, si: SiDef | null): [string, BN, boolean] {
const value = si
? valueBn.div(BN_TEN.pow(new BN(formatBalance.getDefaults().decimals + si.power))).toString()
: valueBn.toString();
return [
value,
valueBn,
true
];
}
Example #11
Source File: embeds.ts From community-repo with GNU General Public License v3.0 | 6 votes |
getWorkerRewardAmountUpdatedEmbed = (reward: RewardRelationship, member: Membership,
blockNumber: number, event: EventRecord): Discord.MessageEmbed => {
return addCommonProperties(new Discord.MessageEmbed()
.setTitle(`??? Salary of ${member.handle} updated`)
.addFields(
{ name: 'Salary', value: formatBalance(reward.amount_per_payout, { withUnit: 'JOY' }), inline: true },
{ name: 'Payout Frequency', value: reward.payout_interval + "", inline: true },
), blockNumber, event );
}
Example #12
Source File: FormatBalance.tsx From subscan-multisig-react with Apache License 2.0 | 6 votes |
function applyFormat(
value: Compact<any> | BN | string,
[decimals, token]: [number, string],
withCurrency = true,
withSi?: boolean,
_isShort?: boolean,
labelPost?: string
): React.ReactNode {
const [prefix, postfix] = formatBalance(value, { decimals, forceUnit: '-', withSi: false }).split('.');
const isShort = _isShort || (withSi && prefix.length >= K_LENGTH);
const unitPost = withCurrency ? token : '';
if (prefix.length > M_LENGTH) {
const [major, rest] = formatBalance(value, { decimals, withUnit: false }).split('.');
const minor = rest.substr(0, 4);
const unit = rest.substr(4);
return (
<>
{major}.<span className="ui--FormatBalance-postfix">{minor}</span>
<span className="ui--FormatBalance-unit">
{unit}
{unit ? unitPost : ` ${unitPost}`}
</span>
{labelPost || ''}
</>
);
}
return createElement(prefix, postfix, unitPost, labelPost, isShort);
}
Example #13
Source File: transferTokens.ts From community-repo with GNU General Public License v3.0 | 6 votes |
private async initApi(
apiUri: string = DEFAULT_API_URI,
): Promise<ApiPromise> {
const wsProvider: WsProvider = new WsProvider(apiUri);
const api = new ApiPromise({
provider: wsProvider,
types,
});
await api.isReadyOrError;
// Initializing some api params based on pioneer/packages/react-api/Api.tsx
const [properties] = await Promise.all([api.rpc.system.properties()]);
const tokenSymbol = properties.tokenSymbol.unwrap()[0].toString();
const tokenDecimals = properties.tokenDecimals.unwrap()[0].toNumber();
// formatBlanace config
formatBalance.setDefaults({
decimals: tokenDecimals,
unit: tokenSymbol,
});
return api;
}
Example #14
Source File: InputCsmNumber.tsx From crust-apps with Apache License 2.0 | 6 votes |
function getSiPowers (si: SiDef | null): [BN, number, number] {
if (!si) {
return [BN_ZERO, 0, 0];
}
const basePower = formatBalance.getDefaults().decimals;
return [new BN(basePower + si.power), basePower, si.power];
}
Example #15
Source File: transferTokens.ts From community-repo with GNU General Public License v3.0 | 5 votes |
async start(recipient: string, amount: number) {
console.log('start transfer', recipient, amount);
await this.init();
const selectedAccount: NamedKeyringPair =
await this.getFaucetAccount();
const amountBN: BN = new BN(amount);
// Initial validation
validateAddress(recipient, 'Invalid recipient address');
const accBalance = await this.getAccountBalancesInfo(selectedAccount.address);
checkBalance(accBalance, amountBN);
await this.requestAccountDecoding(selectedAccount);
console.log(chalk.magentaBright('Estimating fee...'));
const tx = await this.createTransferTx(recipient, amountBN);
let estimatedFee: BN = new BN(0);
try {
estimatedFee = await this.estimateFee(selectedAccount, tx);
} catch (e) {
throw new Error('Could not estimate the fee.');
}
const totalAmount: BN = amountBN.add(estimatedFee);
console.log(
chalk.magentaBright('Estimated fee:', formatBalance(estimatedFee))
);
console.log(
chalk.magentaBright('Total transfer amount:', formatBalance(totalAmount))
);
checkBalance(accBalance, totalAmount);
try {
const txHash: Hash = await tx.signAndSend(selectedAccount);
console.log(chalk.greenBright('Transaction successfully sent!'));
console.log(chalk.magentaBright('Hash:', txHash.toString()));
} catch (e) {
console.error('Could not send the transaction.');
}
}
Example #16
Source File: balances.ts From subsocial-js with GNU General Public License v3.0 | 5 votes |
simpleFormatBalance = (balance: BN | string | number, decimals?: number, currency?: string, withUnit = true) => {
const { unit, decimals: defaultDecimals } = formatBalance.getDefaults()
return formatBalance(balance, { decimals: decimals || defaultDecimals, forceUnit: currency || unit, withUnit })
}
Example #17
Source File: DryRun.tsx From contracts-ui with GNU General Public License v3.0 | 5 votes |
export function DryRun() {
const { api } = useApi();
const { dryRunResult } = useInstantiate();
const dryRunError =
dryRunResult?.result.isErr && dryRunResult?.result.asErr.isModule
? api.registry.findMetaError(dryRunResult?.result.asErr.asModule)
: null;
return (
<SidePanel className="instantiate-outcome" header="Predicted Outcome">
<div className="body">
<div className="row">
<div>Gas Required:</div>
<div>{dryRunResult?.gasRequired && <>{formatNumber(dryRunResult.gasRequired)}</>}</div>
</div>
<div className="row">
<div>Gas Consumed:</div>
<div>{dryRunResult?.gasConsumed && <>{formatNumber(dryRunResult.gasConsumed)}</>}</div>
</div>
<div className="row">
<div>Storage Deposit:</div>
<div>
{dryRunResult?.storageDeposit &&
(() => {
if (dryRunResult.storageDeposit.isCharge) {
if (dryRunResult.storageDeposit.asCharge.eqn(0)) {
return 'None';
}
return formatBalance(dryRunResult.storageDeposit.asCharge, { decimals: 12 });
}
return 'None';
})()}
</div>
</div>
<div className="row h-8">
<div>Contract Address:</div>
<div>
{dryRunResult?.result.isOk ? (
<Account size={26} value={dryRunResult?.result.asOk.accountId.toString()} />
) : (
'None'
)}
</div>
</div>
<div>
{dryRunResult?.result.isOk && (
<div className="validation success font-bold">
<CheckCircleIcon className="mr-3" />
The instantiation will be successful.
</div>
)}
{dryRunError && dryRunResult && (
<>
<div className="validation error text-mono font-bold items-start">
<ExclamationCircleIcon className="mr-3" style={{ marginTop: 1 }} />
<div>
<p>{dryRunError.name}</p>
<p>{dryRunError.docs}</p>
</div>
</div>
{dryRunResult.debugMessage.length > 0 && (
<div className="validation error block text-mono break-words pl-4 mt-1">
{dryRunResult.debugMessage.toString()}
</div>
)}
</>
)}
</div>
</div>
</SidePanel>
);
}
Example #18
Source File: EstimatedFee.tsx From parity-bridges-ui with GNU General Public License v3.0 | 5 votes |
getFormattedAmount = (fee: string | null, chainDecimals: number, chainTokens: string) =>
fee
? formatBalance(fee, {
decimals: chainDecimals,
withUnit: chainTokens,
withSi: true
})
: null
Example #19
Source File: Api.tsx From subscan-multisig-react with Apache License 2.0 | 5 votes |
// eslint-disable-next-line complexity
async function loadOnReady(
api: ApiPromise,
injectedPromise: Promise<InjectedExtension[]>,
store: KeyringStore | undefined,
types: Record<string, Record<string, string>>
): Promise<ApiState> {
registry.register(types);
const { injectedAccounts, properties, systemChain, systemChainType, systemName, systemVersion } = await retrieve(
api,
injectedPromise
);
const ss58Format = settings.prefix === -1 ? properties.ss58Format.unwrapOr(DEFAULT_SS58).toNumber() : settings.prefix;
const tokenSymbol = properties.tokenSymbol.unwrapOr([formatBalance.getDefaults().unit, ...DEFAULT_AUX]);
const tokenDecimals = properties.tokenDecimals.unwrapOr([DEFAULT_DECIMALS]);
const isEthereum = ethereumChains.includes(api.runtimeVersion.specName.toString());
const isDevelopment = systemChainType.isDevelopment || systemChainType.isLocal || isTestChain(systemChain);
// explicitly override the ss58Format as specified
registry.setChainProperties(
registry.createType('ChainProperties', { ss58Format, tokenDecimals, tokenSymbol }) as ChainProperties
);
// first setup the UI helpers
formatBalance.setDefaults({
decimals: (tokenDecimals as BN[]).map((b) => b.toNumber()),
unit: tokenSymbol[0].toString(),
});
TokenUnit.setAbbr(tokenSymbol[0].toString());
// finally load the keyring
const isLoaded = isKeyringLoaded();
if (!isLoaded) {
keyring.loadAll(
{
isDevelopment,
ss58Format,
store,
type: isEthereum ? 'ethereum' : 'ed25519',
},
injectedAccounts
);
}
const defaultSection = Object.keys(api.tx)[0];
const defaultMethod = Object.keys(api.tx[defaultSection])[0];
const apiDefaultTx = api.tx[defaultSection][defaultMethod];
const apiDefaultTxSudo = (api.tx.system && api.tx.system.setCode) || apiDefaultTx;
setDeriveCache(api.genesisHash.toHex(), deriveMapCache);
return {
apiDefaultTx,
apiDefaultTxSudo,
hasInjectedAccounts: injectedAccounts.length !== 0,
isApiReady: true,
isDevelopment: isEthereum ? false : isDevelopment,
isEthereum,
specName: api.runtimeVersion.specName.toString(),
specVersion: api.runtimeVersion.specVersion.toString(),
systemChain,
systemName,
systemVersion,
};
}
Example #20
Source File: TransactionTable.tsx From metamask-snap-polkadot with Apache License 2.0 | 5 votes |
TransactionTable = (props: TransactionTableProps) => {
return (
<TableContainer className="transtaction-table" component={Paper}>
<Table
aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Transaction id</TableCell>
<TableCell align="center">Block</TableCell>
<TableCell align="center">Sender</TableCell>
<TableCell align="center">Destination</TableCell>
<TableCell align="center">Amount</TableCell>
<TableCell align="center">Fee</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.txs.map(tx => (
<TableRow key={tx.hash}>
<TableCell align="left" component="th" scope="row">
{tx.hash}
</TableCell>
<TableCell align="center" component="th" scope="row">
{tx.block}
</TableCell>
<TableCell align="center">{shortAddress(tx.sender)}</TableCell>
<TableCell align="center">{shortAddress(tx.destination)}</TableCell>
<TableCell align="center">{formatBalance(tx.amount, {
decimals: 12,
withSi: true,
withUnit: "KSM"
})}</TableCell>
<TableCell align="center">{formatBalance(tx.fee, {
decimals: 12,
withSi: true,
withUnit: "KSM"
})}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}
Example #21
Source File: InputCsmNumber.tsx From crust-apps with Apache License 2.0 | 5 votes |
function getSiOptions (): { text: string; value: string }[] {
return formatBalance.getOptions().map(({ power, text, value }): { text: string; value: string } => ({
text: text === 'CRU'
? 'CSM'
: text,
value
})).filter(e => e.text === 'CSM');
}
Example #22
Source File: embeds.ts From community-repo with GNU General Public License v3.0 | 5 votes |
getStakeUpdatedEmbed = (stake: Stake, member: Membership, action: string, blockNumber: number, event: EventRecord): Discord.MessageEmbed => {
return addCommonProperties(new Discord.MessageEmbed()
.setTitle(`??? ${member.handle}'s stake has been ${action}`)
.addFields(
{ name: 'Stake', value: formatBalance(stake.value.toString(), { withUnit: 'JOY' }), inline: true }
), blockNumber, event );
}
Example #23
Source File: DemocracyLocks.tsx From crust-apps with Apache License 2.0 | 5 votes |
// group by header & details
// - all unlockable together
// - all ongoing together
// - unlocks are displayed individually
function groupLocks (t: TFunction, bestNumber: BN, locks: DeriveDemocracyLock[] = []): State {
return {
maxBalance: bnMax(...locks.map(({ balance }) => balance)),
sorted: locks
.map((info): [DeriveDemocracyLock, BN] => [info, info.unlockAt.gt(bestNumber) ? info.unlockAt.sub(bestNumber) : BN_ZERO])
.sort((a, b) => a[0].referendumId.cmp(b[0].referendumId))
.sort((a, b) => a[1].cmp(b[1]))
.sort((a, b) => a[0].isFinished === b[0].isFinished ? 0 : (a[0].isFinished ? -1 : 1))
.reduce((sorted: Entry[], [{ balance, isDelegated, isFinished, referendumId, vote }, blocks]): Entry[] => {
const isCountdown = blocks.gt(BN_ZERO);
const header = <div>#{referendumId.toString()} {formatBalance(balance, { forceUnit: '-' })} {vote.conviction.toString()}{isDelegated && '/d'}</div>;
const prev = sorted.length ? sorted[sorted.length - 1] : null;
if (!prev || (isCountdown || (isFinished !== prev.isFinished))) {
sorted.push({
details: (
<div className='faded'>
{isCountdown
? (
<BlockToTime
label={`${t<string>('{{blocks}} blocks', { replace: { blocks: formatNumber(blocks) } })}, `}
value={blocks}
/>
)
: isFinished
? t<string>('lock expired')
: t<string>('ongoing referendum')
}
</div>
),
headers: [header],
isCountdown,
isFinished
});
} else {
prev.headers.push(header);
}
return sorted;
}, [])
};
}
Example #24
Source File: embeds.ts From community-repo with GNU General Public License v3.0 | 5 votes |
getMintCapacityChangedEmbed = (minted: number, mint: u128, blockNumber: number, event: EventRecord): Discord.MessageEmbed => {
return addCommonProperties(new Discord.MessageEmbed()
.setTitle(`? ? ? ? ? ${formatBalance(minted, { withUnit: 'JOY' })} minted to the Treasury ? ? ? ? ? `)
.addFields(
{ name: 'Balance', value: formatBalance(mint, { withUnit: 'JOY' }), inline: true },
), blockNumber, event );
}
Example #25
Source File: InputNumber.tsx From subscan-multisig-react with Apache License 2.0 | 4 votes |
function InputNumber({
autoFocus,
bitLength = DEFAULT_BITLENGTH,
children,
className = '',
defaultValue,
help,
isDecimal,
isFull,
isSi,
isDisabled,
isError = false,
isWarning,
isZeroable = true,
label,
labelExtra,
maxLength,
maxValue,
onChange,
onEnter,
onEscape,
placeholder,
siDecimals,
siDefault,
siSymbol,
value: propsValue,
}: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const [si, setSi] = useState<SiDef | null>(() => (isSi ? siDefault || formatBalance.findSi('-') : null));
const [[value, valueBn, isValid], setValues] = useState<[string, BN, boolean]>(() =>
getValues(api, propsValue || defaultValue, si, bitLength, isZeroable, maxValue, siDecimals)
);
const [isPreKeyDown, setIsPreKeyDown] = useState(false);
const siOptions = useMemo(() => getSiOptions(siSymbol || TokenUnit.abbr, siDecimals), [siDecimals, siSymbol]);
useEffect((): void => {
// eslint-disable-next-line
onChange && onChange(isValid ? valueBn : undefined);
}, [isValid, onChange, valueBn]);
const _onChangeWithSi = useCallback(
(input: string, si: SiDef | null) =>
setValues(getValuesFromString(api, input, si, bitLength, isZeroable, maxValue, siDecimals)),
[api, bitLength, isZeroable, maxValue, siDecimals]
);
const _onChange = useCallback((input: string) => _onChangeWithSi(input, si), [_onChangeWithSi, si]);
useEffect((): void => {
// eslint-disable-next-line
defaultValue && _onChange(defaultValue.toString());
}, [_onChange, defaultValue]);
const _onKeyDown = useCallback(
(event: React.KeyboardEvent<Element>): void => {
if (KEYS_PRE.includes(event.key)) {
setIsPreKeyDown(true);
return;
}
if (event.key.length === 1 && !isPreKeyDown) {
const { selectionEnd: j, selectionStart: i, value } = event.target as HTMLInputElement;
const newValue = `${value.substring(0, i || 0)}${event.key}${value.substring(j || 0)}`;
if (!getRegex(isDecimal || !!si).test(newValue)) {
event.preventDefault();
}
}
},
[isDecimal, isPreKeyDown, si]
);
const _onKeyUp = useCallback((event: React.KeyboardEvent<Element>): void => {
if (KEYS_PRE.includes(event.key)) {
setIsPreKeyDown(false);
}
}, []);
const _onPaste = useCallback(
(event: React.ClipboardEvent<Element>): void => {
const { value: newValue } = event.target as HTMLInputElement;
if (!getRegex(isDecimal || !!si).test(newValue)) {
event.preventDefault();
}
},
[isDecimal, si]
);
const _onSelectSiUnit = useCallback(
(siUnit: string): void => {
const si = formatBalance.findSi(siUnit);
setSi(si);
_onChangeWithSi(value, si);
},
[_onChangeWithSi, value]
);
// Same as the number of digits, which means it can still overflow, i.e.
// for u8 we allow 3, which could be 999 (however 2 digits will limit to only 99,
// so this is more-or-less the lesser of evils without a max-value check)
const maxValueLength = getGlobalMaxValue(bitLength).toString().length;
return (
<Input
autoFocus={autoFocus}
className={`ui--InputNumber${isDisabled ? ' isDisabled' : ''} ${className}`}
help={help}
isAction={isSi}
isDisabled={isDisabled}
isError={!isValid || isError}
isFull={isFull}
isWarning={isWarning}
label={label}
labelExtra={labelExtra}
maxLength={maxLength || maxValueLength}
onChange={_onChange}
onEnter={onEnter}
onEscape={onEscape}
onKeyDown={_onKeyDown}
onKeyUp={_onKeyUp}
onPaste={_onPaste}
placeholder={placeholder || t<string>('Positive number')}
type="text"
value={value}
>
{!!si && (
<Dropdown
defaultValue={si.value}
dropdownClassName="ui--SiDropdown"
isButton
onChange={_onSelectSiUnit}
options={siOptions}
/>
)}
{children}
</Input>
);
}
Example #26
Source File: Account.tsx From crust-apps with Apache License 2.0 | 4 votes |
function Account ({ account: { address, meta }, className = '', delegation, filter, isFavorite, proxy, setBalance, toggleFavorite }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { theme } = useContext<ThemeDef>(ThemeContext);
const { queueExtrinsic } = useContext(StatusContext);
const api = useApi();
const { getLedger } = useLedger();
const bestNumber = useBestNumber();
const balancesAll = useCall<DeriveBalancesAll>(api.api.derive.balances.all, [address]);
const democracyLocks = useCall<DeriveDemocracyLock[]>(api.api.derive.democracy?.locks, [address]);
const recoveryInfo = useCall<RecoveryConfig | null>(api.api.query.recovery?.recoverable, [address], transformRecovery);
const multiInfos = useMultisigApprovals(address);
const proxyInfo = useProxies(address);
const { flags: { isDevelopment, isEditable, isExternal, isHardware, isInjected, isMultisig, isProxied }, genesisHash, identity, name: accName, onSetGenesisHash, tags } = useAccountInfo(address);
const [{ democracyUnlockTx }, setUnlockableIds] = useState<DemocracyUnlockable>({ democracyUnlockTx: null, ids: [] });
const [vestingVestTx, setVestingTx] = useState<SubmittableExtrinsic<'promise'> | null>(null);
const [isBackupOpen, toggleBackup] = useToggle();
const [isDeriveOpen, toggleDerive] = useToggle();
const [isForgetOpen, toggleForget] = useToggle();
const [isIdentityMainOpen, toggleIdentityMain] = useToggle();
const [isIdentitySubOpen, toggleIdentitySub] = useToggle();
const [isMultisigOpen, toggleMultisig] = useToggle();
const [isProxyOverviewOpen, toggleProxyOverview] = useToggle();
const [isPasswordOpen, togglePassword] = useToggle();
const [isRecoverAccountOpen, toggleRecoverAccount] = useToggle();
const [isRecoverSetupOpen, toggleRecoverSetup] = useToggle();
const [isSettingsOpen, toggleSettings] = useToggle();
const [isTransferOpen, toggleTransfer] = useToggle();
const [isDelegateOpen, toggleDelegate] = useToggle();
const [isUndelegateOpen, toggleUndelegate] = useToggle();
const candyAmount = useCall<Balance>(api.api.query.candy?.balances, [address]);
const [isTransferCandyOpen, toggleTransferCandy] = useToggle();
const [isTransferCsmOpen, toggleTransferCsm] = useToggle();
useEffect((): void => {
if (balancesAll) {
setBalance(address, balancesAll.freeBalance.add(balancesAll.reservedBalance));
api.api.tx.vesting?.vest && setVestingTx(() =>
balancesAll.vestingLocked.isZero()
? null
: api.api.tx.vesting.vest()
);
}
}, [address, api, balancesAll, setBalance]);
useEffect((): void => {
bestNumber && democracyLocks && setUnlockableIds(
(prev): DemocracyUnlockable => {
const ids = democracyLocks
.filter(({ isFinished, unlockAt }) => isFinished && bestNumber.gt(unlockAt))
.map(({ referendumId }) => referendumId);
if (JSON.stringify(prev.ids) === JSON.stringify(ids)) {
return prev;
}
return {
democracyUnlockTx: createClearDemocracyTx(api.api, address, ids),
ids
};
}
);
}, [address, api, bestNumber, democracyLocks]);
const isVisible = useMemo(
() => calcVisible(filter, accName, tags),
[accName, filter, tags]
);
const _onFavorite = useCallback(
() => toggleFavorite(address),
[address, toggleFavorite]
);
const _onForget = useCallback(
(): void => {
if (!address) {
return;
}
const status: Partial<ActionStatus> = {
account: address,
action: 'forget'
};
try {
keyring.forgetAccount(address);
status.status = 'success';
status.message = t<string>('account forgotten');
} catch (error) {
status.status = 'error';
status.message = (error as Error).message;
}
},
[address, t]
);
const _clearDemocracyLocks = useCallback(
() => democracyUnlockTx && queueExtrinsic({
accountId: address,
extrinsic: democracyUnlockTx
}),
[address, democracyUnlockTx, queueExtrinsic]
);
const _vestingVest = useCallback(
() => vestingVestTx && queueExtrinsic({
accountId: address,
extrinsic: vestingVestTx
}),
[address, queueExtrinsic, vestingVestTx]
);
const _showOnHardware = useCallback(
// TODO: we should check the hardwareType from metadata here as well,
// for now we are always assuming hardwareType === 'ledger'
(): void => {
showLedgerAddress(getLedger, meta).catch((error): void => {
console.error(`ledger: ${(error as Error).message}`);
});
},
[getLedger, meta]
);
const menuItems = useMemo(() => [
createMenuGroup('identityGroup', [
isFunction(api.api.tx.identity?.setIdentity) && !isHardware && (
<Menu.Item
key='identityMain'
onClick={toggleIdentityMain}
>
{t('Set on-chain identity')}
</Menu.Item>
),
isFunction(api.api.tx.identity?.setSubs) && identity?.display && !isHardware && (
<Menu.Item
key='identitySub'
onClick={toggleIdentitySub}
>
{t('Set on-chain sub-identities')}
</Menu.Item>
),
isFunction(api.api.tx.democracy?.unlock) && democracyUnlockTx && (
<Menu.Item
key='clearDemocracy'
onClick={_clearDemocracyLocks}
>
{t('Clear expired democracy locks')}
</Menu.Item>
),
isFunction(api.api.tx.vesting?.vest) && vestingVestTx && (
<Menu.Item
key='vestingVest'
onClick={_vestingVest}
>
{t('Unlock vested amount')}
</Menu.Item>
)
]),
createMenuGroup('deriveGroup', [
!(isExternal || isHardware || isInjected || isMultisig) && (
<Menu.Item
key='deriveAccount'
onClick={toggleDerive}
>
{t('Derive account via derivation path')}
</Menu.Item>
),
isHardware && (
<Menu.Item
key='showHwAddress'
onClick={_showOnHardware}
>
{t('Show address on hardware device')}
</Menu.Item>
)
]),
createMenuGroup('backupGroup', [
!(isExternal || isHardware || isInjected || isMultisig || isDevelopment) && (
<Menu.Item
key='backupJson'
onClick={toggleBackup}
>
{t('Create a backup file for this account')}
</Menu.Item>
),
!(isExternal || isHardware || isInjected || isMultisig || isDevelopment) && (
<Menu.Item
key='changePassword'
onClick={togglePassword}
>
{t("Change this account's password")}
</Menu.Item>
),
!(isInjected || isDevelopment) && (
<Menu.Item
key='forgetAccount'
onClick={toggleForget}
>
{t('Forget this account')}
</Menu.Item>
)
]),
isFunction(api.api.tx.recovery?.createRecovery) && createMenuGroup('reoveryGroup', [
!recoveryInfo && (
<Menu.Item
key='makeRecoverable'
onClick={toggleRecoverSetup}
>
{t('Make recoverable')}
</Menu.Item>
),
<Menu.Item
key='initRecovery'
onClick={toggleRecoverAccount}
>
{t('Initiate recovery for another')}
</Menu.Item>
]),
isFunction(api.api.tx.multisig?.asMulti) && isMultisig && createMenuGroup('multisigGroup', [
<Menu.Item
disabled={!multiInfos || !multiInfos.length}
key='multisigApprovals'
onClick={toggleMultisig}
>
{t('Multisig approvals')}
</Menu.Item>
]),
isFunction(api.api.query.democracy?.votingOf) && delegation?.accountDelegated && createMenuGroup('undelegateGroup', [
<Menu.Item
key='changeDelegate'
onClick={toggleDelegate}
>
{t('Change democracy delegation')}
</Menu.Item>,
<Menu.Item
key='undelegate'
onClick={toggleUndelegate}
>
{t('Undelegate')}
</Menu.Item>
]),
isFunction(api.api.query.democracy?.votingOf) && !delegation?.accountDelegated && createMenuGroup('delegateGroup', [
<Menu.Item
key='delegate'
onClick={toggleDelegate}
>
{t('Delegate democracy votes')}
</Menu.Item>
]),
isFunction(api.api.query.proxy?.proxies) && createMenuGroup('proxyGroup', [
<Menu.Item
key='proxy-overview'
onClick={toggleProxyOverview}
>
{proxy?.[0].length
? t('Manage proxies')
: t('Add proxy')
}
</Menu.Item>
]),
isEditable && !api.isDevelopment && createMenuGroup('genesisGroup', [
<ChainLock
className='accounts--network-toggle'
genesisHash={genesisHash}
key='chainlock'
onChange={onSetGenesisHash}
/>
])
].filter((i) => i),
[_clearDemocracyLocks, _showOnHardware, _vestingVest, api, delegation, democracyUnlockTx, genesisHash, identity, isDevelopment, isEditable, isExternal, isHardware, isInjected, isMultisig, multiInfos, onSetGenesisHash, proxy, recoveryInfo, t, toggleBackup, toggleDelegate, toggleDerive, toggleForget, toggleIdentityMain, toggleIdentitySub, toggleMultisig, togglePassword, toggleProxyOverview, toggleRecoverAccount, toggleRecoverSetup, toggleUndelegate, vestingVestTx]);
if (!isVisible) {
return null;
}
return (
<tr className={className}>
<td className='favorite'>
<Icon
color={isFavorite ? 'orange' : 'gray'}
icon='star'
onClick={_onFavorite}
/>
</td>
<td className='together'>
{meta.genesisHash
? <Badge color='transparent' />
: isDevelopment
? (
<Badge
className='devBadge'
color='orange'
hover={t<string>('This is a development account derived from the known development seed. Do not use for any funds on a non-development network.')}
icon='wrench'
/>
)
: (
<Badge
color='orange'
hover={
<div>
<p>{t<string>('This account is available on all networks. It is recommended to link to a specific network via the account options ("only this network" option) to limit availability. For accounts from an extension, set the network on the extension.')}</p>
<p>{t<string>('This does not send any transaction, rather is only sets the genesis in the account JSON.')}</p>
</div>
}
icon='exclamation-triangle'
/>
)
}
{recoveryInfo && (
<Badge
color='green'
hover={
<div>
<p>{t<string>('This account is recoverable, with the following friends:')}</p>
<div>
{recoveryInfo.friends.map((friend, index): React.ReactNode => (
<IdentityIcon
key={index}
value={friend}
/>
))}
</div>
<table>
<tbody>
<tr>
<td>{t<string>('threshold')}</td>
<td>{formatNumber(recoveryInfo.threshold)}</td>
</tr>
<tr>
<td>{t<string>('delay')}</td>
<td>{formatNumber(recoveryInfo.delayPeriod)}</td>
</tr>
<tr>
<td>{t<string>('deposit')}</td>
<td>{formatBalance(recoveryInfo.deposit)}</td>
</tr>
</tbody>
</table>
</div>
}
icon='shield'
/>
)}
{multiInfos && multiInfos.length !== 0 && (
<Badge
color='red'
hover={t<string>('Multisig approvals pending')}
info={multiInfos.length}
/>
)}
{isProxied && !proxyInfo.hasOwned && (
<Badge
color='red'
hover={t<string>('Proxied account has no owned proxies')}
info='0'
/>
)}
{delegation?.accountDelegated && (
<Badge
color='blue'
hover={t<string>('This account has a governance delegation')}
icon='calendar-check'
onClick={toggleDelegate}
/>
)}
{!!proxy?.[0].length && api.api.tx.utility && (
<Badge
color='blue'
hover={t<string>('This account has {{proxyNumber}} proxy set.', {
replace: {
proxyNumber: proxy[0].length
}
})}
icon='arrow-right'
onClick={toggleProxyOverview}
/>
)}
</td>
<td className='address'>
<AddressSmall value={address} />
{isBackupOpen && (
<Backup
address={address}
key='modal-backup-account'
onClose={toggleBackup}
/>
)}
{isDelegateOpen && (
<DelegateModal
key='modal-delegate'
onClose={toggleDelegate}
previousAmount={delegation?.amount}
previousConviction={delegation?.conviction}
previousDelegatedAccount={delegation?.accountDelegated}
previousDelegatingAccount={address}
/>
)}
{isDeriveOpen && (
<Derive
from={address}
key='modal-derive-account'
onClose={toggleDerive}
/>
)}
{isForgetOpen && (
<Forget
address={address}
key='modal-forget-account'
onClose={toggleForget}
onForget={_onForget}
/>
)}
{isIdentityMainOpen && (
<IdentityMain
address={address}
key='modal-identity-main'
onClose={toggleIdentityMain}
/>
)}
{isIdentitySubOpen && (
<IdentitySub
address={address}
key='modal-identity-sub'
onClose={toggleIdentitySub}
/>
)}
{isPasswordOpen && (
<ChangePass
address={address}
key='modal-change-pass'
onClose={togglePassword}
/>
)}
{isTransferOpen && (
<Transfer
key='modal-transfer'
onClose={toggleTransfer}
senderId={address}
/>
)}
{isTransferCandyOpen && (
<TransferCandy
key='modal-transfer'
onClose={toggleTransferCandy}
senderId={address}
/>
)}
{isTransferCsmOpen && (
<TransferCsm
key='modal-transfer'
onClose={toggleTransferCsm}
senderId={address}
/>
)}
{isProxyOverviewOpen && (
<ProxyOverview
key='modal-proxy-overview'
onClose={toggleProxyOverview}
previousProxy={proxy}
proxiedAccount={address}
/>
)}
{isMultisigOpen && multiInfos && (
<MultisigApprove
address={address}
key='multisig-approve'
onClose={toggleMultisig}
ongoing={multiInfos}
threshold={meta.threshold as number}
who={meta.who as string[]}
/>
)}
{isRecoverAccountOpen && (
<RecoverAccount
address={address}
key='recover-account'
onClose={toggleRecoverAccount}
/>
)}
{isRecoverSetupOpen && (
<RecoverSetup
address={address}
key='recover-setup'
onClose={toggleRecoverSetup}
/>
)}
{isUndelegateOpen && (
<UndelegateModal
accountDelegating={address}
key='modal-delegate'
onClose={toggleUndelegate}
/>
)}
</td>
{/* <td className='address media--1400'>
{(meta.parentAddress as string) && (
<AddressMini value={meta.parentAddress} />
)}
</td> */}
<td className='address media--1400'>
<CryptoType accountId={address} />
</td>
{/* <td className='all'>
<div className='tags'>
<Tags value={tags} />
</div>
</td> */}
<td className='all'>
{balancesAll?.accountNonce.gt(BN_ZERO) && formatNumber(balancesAll.accountNonce)}
</td>
<td className='number'>
<AddressInfo
address={address}
withBalance
withBalanceToggle
withExtended={false}
/>
</td>
<td className='number'>
<AddressCsmInfo address={address}
withBalance
withBalanceToggle
withExtended={false} />
</td>
<td className='number'>
<FormatCandy value={candyAmount} />
</td>
<td className='number'>
<PreClaimCRU18 value={address} />
</td>
<td className='button'>
{/* {isFunction(api.api.tx.balances?.transfer) && (
<Button
icon='paper-plane'
label={t<string>('Send CRU')}
onClick={toggleTransfer}
/>
)} */}
<Popup
className='my-popup'
on='click'
trigger={<Button
icon='paper-plane'
label={t<string>('Send')}
/>}
>
{isFunction(api.api.tx.balances?.transfer) && (
<Button
icon='paper-plane'
label={t<string>('Send CRU')}
onClick={toggleTransfer}
/>
)}
{isFunction(api.api.tx.csm?.transfer) && (
<Button
icon='paper-plane'
label={t<string>('Send CSM')}
onClick={toggleTransferCsm}
/>
)}
{isFunction(api.api.tx.candy?.transfer) && (
<Button
icon='paper-plane'
label={t<string>('Send Candy')}
onClick={toggleTransferCandy}
/>
)}
</Popup>
<Popup
className={`theme--${theme}`}
isOpen={isSettingsOpen}
onClose={toggleSettings}
trigger={
<Button
icon='ellipsis-v'
isDisabled={!menuItems.length}
onClick={toggleSettings}
/>
}
>
<Menu
onClick={toggleSettings}
text
vertical
>
{menuItems}
</Menu>
</Popup>
</td>
<td className='links media--1400'>
<LinkExternal
className='ui--AddressCard-exporer-link'
data={address}
isLogo
type='address'
/>
</td>
</tr>
);
}
Example #27
Source File: AddressInfo.tsx From subscan-multisig-react with Apache License 2.0 | 4 votes |
function createBalanceItems(
formatIndex: number,
lookup: Record<string, string>,
t: TFunction,
{
address,
balanceDisplay,
balancesAll,
bestNumber,
democracyLocks,
isAllLocked,
otherBonded,
ownBonded,
stakingInfo,
votingOf,
withBalanceToggle,
}: {
address: string;
balanceDisplay: BalanceActiveType;
balancesAll?: DeriveBalancesAll | DeriveBalancesAccountData;
bestNumber: BlockNumber;
democracyLocks?: DeriveDemocracyLock[];
isAllLocked: boolean;
otherBonded: BN[];
ownBonded: BN;
stakingInfo?: DeriveStakingAccount;
votingOf?: Voting;
withBalanceToggle: boolean;
}
): React.ReactNode {
const allItems: React.ReactNode[] = [];
const deriveBalances = balancesAll as DeriveBalancesAll;
// eslint-disable-next-line
!withBalanceToggle &&
balancesAll &&
balanceDisplay.total &&
allItems.push(
<React.Fragment key={0}>
<Label label={t<string>('total')} />
<FormatBalance
className="result"
formatIndex={formatIndex}
value={balancesAll.freeBalance.add(balancesAll.reservedBalance)}
/>
</React.Fragment>
);
// eslint-disable-next-line
balancesAll &&
balanceDisplay.available &&
(balancesAll as DeriveBalancesAll).availableBalance &&
allItems.push(
<React.Fragment key={1}>
<Label label={t<string>('transferrable')} />
<FormatBalance
className="result"
formatIndex={formatIndex}
value={(balancesAll as DeriveBalancesAll).availableBalance}
/>
</React.Fragment>
);
if (balanceDisplay.vested && deriveBalances?.isVesting) {
const allVesting = deriveBalances.vesting.filter(({ endBlock }) => bestNumber.lt(endBlock));
allItems.push(
<React.Fragment key={2}>
<Label label={t<string>('vested')} />
<FormatBalance
className='result'
formatIndex={formatIndex}
labelPost={
<Icon
icon='info-circle'
tooltip={`${address}-vested-trigger`}
/>
}
value={deriveBalances.vestedBalance}
>
<Tooltip
text={
<>
<div>
{formatBalance(deriveBalances.vestedClaimable, { forceUnit: '-' })}
<div className='faded'>{t('available to be unlocked')}</div>
</div>
{allVesting.map(({ endBlock, locked, perBlock, vested }, index) => (
<div
className='inner'
key={`item:${index}`}
>
<div>
{formatBalance(vested, { forceUnit: '-' })}
<div className='faded'>{t('of {{locked}} vested', { replace: { locked: formatBalance(locked, { forceUnit: '-' }) } })}</div>
</div>
<div>
<BlockToTime value={endBlock.sub(bestNumber)} />
<div className='faded'>{t('until block')} {formatNumber(endBlock)}</div>
</div>
<div>
{formatBalance(perBlock)}
<div className='faded'>{t('per block')}</div>
</div>
</div>
))}
</>
}
trigger={`${address}-vested-trigger`}
/>
</FormatBalance>
</React.Fragment>
);
}
balanceDisplay.locked &&
balancesAll &&
(isAllLocked || (balancesAll as DeriveBalancesAll).lockedBalance?.gtn(0)) &&
allItems.push(
<React.Fragment key={3}>
<Label label={t<string>('locked')} />
<FormatBalance
className="result"
formatIndex={formatIndex}
label={<Icon icon="info-circle" tooltip={`${address}-locks-trigger`} />}
value={isAllLocked ? 'all' : (balancesAll as DeriveBalancesAll).lockedBalance}
>
<Tooltip
text={(balancesAll as DeriveBalancesAll).lockedBreakdown.map(
({ amount, id, reasons }, index): React.ReactNode => (
<div key={index}>
{amount?.isMax() ? t<string>('everything') : formatBalance(amount, { forceUnit: '-' })}
{id && <div className="faded">{lookupLock(lookup, id)}</div>}
<div className="faded">{reasons.toString()}</div>
</div>
)
)}
trigger={`${address}-locks-trigger`}
/>
</FormatBalance>
</React.Fragment>
);
balanceDisplay.reserved &&
balancesAll?.reservedBalance?.gtn(0) &&
allItems.push(
<React.Fragment key={4}>
<Label label={t<string>('reserved')} />
<FormatBalance className="result" formatIndex={formatIndex} value={balancesAll.reservedBalance} />
</React.Fragment>
);
balanceDisplay.bonded &&
(ownBonded.gtn(0) || otherBonded.length !== 0) &&
allItems.push(
<React.Fragment key={5}>
<Label label={t<string>('bonded')} />
<FormatBalance className="result" formatIndex={formatIndex} value={ownBonded}>
{otherBonded.length !== 0 && (
<>
(+
{otherBonded.map(
(bonded, index): React.ReactNode => (
<FormatBalance formatIndex={formatIndex} key={index} value={bonded} />
)
)}
)
</>
)}
</FormatBalance>
</React.Fragment>
);
balanceDisplay.redeemable &&
stakingInfo?.redeemable?.gtn(0) &&
allItems.push(
<React.Fragment key={6}>
<Label label={t<string>('redeemable')} />
<StakingRedeemable className="result" stakingInfo={stakingInfo} />
</React.Fragment>
);
if (balanceDisplay.unlocking) {
stakingInfo?.unlocking &&
allItems.push(
<React.Fragment key={7}>
<Label label={t<string>('unbonding')} />
<div className="result">
<StakingUnbonding stakingInfo={stakingInfo} />
</div>
</React.Fragment>
);
if (democracyLocks && democracyLocks.length !== 0) {
allItems.push(
<React.Fragment key={8}>
<Label label={t<string>('democracy')} />
<div className="result">
<DemocracyLocks value={democracyLocks} />
</div>
</React.Fragment>
);
} else if (votingOf && votingOf.isDirect) {
const {
prior: [unlockAt, balance],
} = votingOf.asDirect;
balance.gt(BN_ZERO) &&
unlockAt.gt(BN_ZERO) &&
allItems.push(
<React.Fragment key={8}>
<Label label={t<string>('democracy')} />
<div className="result">
<DemocracyLocks value={[{ balance, isFinished: bestNumber.gt(unlockAt), unlockAt }]} />
</div>
</React.Fragment>
);
}
}
if (withBalanceToggle) {
return (
<React.Fragment key={formatIndex}>
<Expander
summary={
<FormatBalance
formatIndex={formatIndex}
value={balancesAll && balancesAll.freeBalance.add(balancesAll.reservedBalance)}
/>
}
>
{allItems.length !== 0 && <div className="body column">{allItems}</div>}
</Expander>
</React.Fragment>
);
}
return <React.Fragment key={formatIndex}>{allItems}</React.Fragment>;
}
Example #28
Source File: index.tsx From crust-apps with Apache License 2.0 | 4 votes |
function EthereumAssets ({ className = '', senderId: propSenderId }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api, systemChain } = useApi();
const [amount, setAmount] = useState<BN | undefined>(BN_ZERO);
const [hasAvailable] = useState(true);
const [senderId, setSenderId] = useState<string | null>(propSenderId || null);
const [ethereumAddress, setEthereumAddress] = useState<string | undefined | null>(null);
const [isValid, setIsValid] = useState(false);
const [bridgeFee, setBridgeFee] = useState<BN>(BN_ZERO);
const isMaxwell = systemChain === 'Crust Maxwell';
const bridgeTxStatusLink = isMaxwell ? 'https://etherscan.io/address/0x9d332427e6d1b91d9cf8d2fa3b41df2012887aab' : 'https://etherscan.io/address/0x18FCb27e4712AC11B8BecE851DAF96ba8ba34720';
const whitePot = isMaxwell ? 0 : 2
const [handlerAsset, setHandlerAsset] = useState<BN | undefined>(BN_ZERO);
useEffect(() => {
api.query.bridgeTransfer.bridgeFee(whitePot).then((bridgeFee) => {
const fee = JSON.parse(JSON.stringify(bridgeFee));
setBridgeFee(new BN(Number(fee[0]).toString()));
});
}, [api]);
useEffect(() => {
const provider = ethers.getDefaultProvider();
const erc20Contract = new ethers.Contract(contractAddress, abi, provider);
erc20Contract.getBalance(handler).then((res: any) => {
setHandlerAsset(new BN((Number(res) / 1000000.0).toString()))
})
}, [])
const onChangeEthereumAddress = useCallback((hex: string) => {
const isValidEthAddr = hex.startsWith('0x') && ethers.utils.isAddress(hex);
if (isValidEthAddr) {
setIsValid(true);
} else {
setIsValid(false);
}
setEthereumAddress(hex.trim());
}, []);
// const onChangeEthereumAddress = useCallback((value: string) => {
// // FIXME We surely need a better check than just a trim
// setEthereumAddress(value.trim());
// }, []);
return (<div className={className}>
<Columar>
<Columar.Column>
<Card withBottomMargin>
<Banner type='warning'>
<p>{t<string>('This function is an internal test stage, the assets will not be lost, but there may be a delay (max to 48 hours) in the arrival of the account.')}</p>
</Banner>
<h3><span style={{ fontWeight: 'bold' }}>{t<string>('From Crust')}</span></h3>
<div style={{ display: 'flex' }}>
<img src={logoCrust as string}
style={{ width: '64px', height: '64px', padding: '1px', verticalAlign: 'middle' }} />
<div style={{ flex: 1, verticalAlign: 'middle' }}>
<InputAddress
defaultValue={propSenderId}
help={t<string>('The account you will sign tx.')}
isDisabled={!!propSenderId}
label={t<string>('account')}
onChange={setSenderId}
labelExtra={
<Available
label={t('transferrable')}
params={senderId}
/>
}
type='account'
/>
</div>
</div>
<h3><span style={{ fontWeight: 'bold' }}>{t<string>('To Ethereum')}</span></h3>
<div style={{ display: 'flex', alignItems: 'middle' }}>
<img src={ethereumLogo as string}
style={{ width: '64px', height: '64px', padding: '3px', verticalAlign: 'middle' }} />
<div style={{ flex: 1, verticalAlign: 'middle' }}>
<Input
autoFocus
className='full'
help={t<string>('The Ethereum address')}
isError={!isValid}
label={t<string>('Ethereum address')}
onChange={onChangeEthereumAddress}
placeholder={t<string>('0x prefixed hex')}
value={ethereumAddress || ''}
/>
</div>
</div>
<h3><span style={{ fontWeight: 'bold' }}>{t<string>('Amount')}</span></h3>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ width: '64px', verticalAlign: 'middle' }}/>
<div style={{ flex: 1, verticalAlign: 'middle' }}>
<InputBalance
autoFocus
help={t<string>('Type the amount you want to transfer. Note that you can select the unit on the right e.g sending 1 milli is equivalent to sending 0.001.')}
isError={!hasAvailable}
label={t<string>('amount')}
onChange={setAmount}
withMax
/>
<MarkWarning content={t<string>('The transaction fee is ')}>
<span style={{'color': '#ff8812', 'textDecoration': 'underline', 'fontStyle': 'italic'}}>{formatBalance(bridgeFee)}</span> <span>{t<string>('(The transaction fee will be dynamically adjusted according to the Gwei of Ethereum)')}</span>
</MarkWarning>
</div>
</div>
<Button.Group>
<TxButton
accountId={senderId}
icon='paper-plane'
isDisabled={!isValid || (handlerAsset && amount && handlerAsset.lte(amount))}
label={t<string>('Transfer')}
params={[amount, ethereumAddress, whitePot]}
tx={api.tx.bridgeTransfer?.transferNative}
/>
</Button.Group>
</Card>
</Columar.Column>
<Columar.Column>
<Card>
<Banner type="warning">
<p>{t<string>('Cross-chain transfers are automatically executed by smart contracts. after the execution of the contract is completed, the funds will arrive in the account. Please wait patiently.')} <a target="_blank" href={bridgeTxStatusLink}>{t<string>('You can check the transaction status here...')}</a></p>
</Banner>
</Card>
</Columar.Column>
</Columar>
</div>);
}
Example #29
Source File: useApiCalls.ts From parity-bridges-ui with GNU General Public License v3.0 | 4 votes |
useApiCalls = (): ApiCallsContextType => {
const { sourceChainDetails, targetChainDetails } = useSourceTarget();
const {
apiConnection: { api: sourceApi },
chain: sourceChain
} = sourceChainDetails;
const { keyringPairs, keyringPairsReady } = useKeyringContext();
const { getValuesByChain } = useChainGetters();
const createType = useCallback(
(chain, type, data) => {
const { api } = getValuesByChain(chain);
return api.registry.createType(type, data);
},
[getValuesByChain]
);
const stateCall = useCallback(
(chain: string, methodName: string | Text, data: string | Uint8Array | Bytes, at) => {
const { api } = getValuesByChain(chain);
const params: [string | Text, string | Uint8Array | Bytes] = [methodName, data];
if (at) {
params.push(at);
}
return api.rpc.state.call<Codec>(...params);
},
[getValuesByChain]
);
const internalTransfer = useCallback(
async (dispatchers, transfersData) => {
const { dispatchTransaction, dispatchMessage } = dispatchers;
const { receiverAddress, transferAmount, account } = transfersData;
const type = TransactionTypes.INTERNAL_TRANSFER;
const id = Date.now().toString();
dispatchTransaction(TransactionActionCreators.setTransactionRunning(true));
try {
const transfer = sourceApi.tx.balances.transfer(receiverAddress, transferAmount);
const options: Partial<SignerOptions> = {
nonce: -1
};
let sourceAccount: string | KeyringPair = account;
if (account.meta.isInjected) {
const injector = await web3FromSource(account.meta.source as string);
options.signer = injector.signer;
sourceAccount = account.address;
}
const transactionDisplayPayload = {
sourceAccount: account?.address || sourceAccount,
transferAmount: transferAmount.toNumber(),
receiverAddress
};
const unsub = await transfer.signAndSend(sourceAccount, { ...options }, async ({ status }) => {
const steps = createEmptyInternalSteps(sourceChain);
if (status.isReady) {
dispatchTransaction(
TransactionActionCreators.createTransactionStatus({
block: null,
blockHash: null,
deliveryBlock: null,
id,
input: transferAmount,
messageNonce: null,
receiverAddress,
sourceAccount: account.address,
senderName: getName(account),
sourceChain,
status: TransactionStatusEnum.IN_PROGRESS,
targetChain: '',
type,
transactionDisplayPayload,
payloadHex: transfer.toHex(),
steps
})
);
}
if (status.isBroadcast) {
dispatchMessage(MessageActionsCreators.triggerInfoMessage({ message: 'Transaction was broadcasted' }));
dispatchTransaction(TransactionActionCreators.reset());
}
if (status.isInBlock) {
try {
const res = (await sourceApi.rpc.chain.getBlock(status.asInBlock)) as SignedBlock;
const block = res.block.header.number.toString();
dispatchTransaction(
TransactionActionCreators.updateTransactionStatus(
{
block,
blockHash: status.asInBlock.toString()
},
id
)
);
} catch (e) {
if (e instanceof Error) {
logger.error(e.message);
throw new Error('Issue reading block information.');
}
}
}
if (status.isFinalized) {
dispatchTransaction(
TransactionActionCreators.updateTransactionStatus(
{
status: TransactionStatusEnum.FINALIZED
},
id
)
);
logger.info(`Transaction finalized at blockHash ${status.asFinalized}`);
unsub();
}
});
} catch (e) {
if (e instanceof Error) {
dispatchMessage(MessageActionsCreators.triggerErrorMessage({ message: e.message }));
logger.error(e.message);
}
} finally {
dispatchTransaction(TransactionActionCreators.setTransactionRunning(false));
}
},
[sourceApi.rpc.chain, sourceApi.tx.balances, sourceChain]
);
const updateSenderAccountsInformation = useCallback(
async (dispatchAccount) => {
const formatBalanceAddress = (data: any, api: ApiPromise): BalanceState => {
return {
chainTokens: data.registry.chainTokens[0],
formattedBalance: formatBalance(data.free, {
decimals: api.registry.chainDecimals[0],
withUnit: api.registry.chainTokens[0],
withSi: true
}),
free: data.free
};
};
if (!keyringPairsReady || !keyringPairs.length) {
return {};
}
const getAccountInformation = async (sourceRole: any, targetRole: any) => {
const {
apiConnection: { api: sourceApi },
chain: sourceChain,
configs: sourceConfigs
} = sourceRole;
const {
apiConnection: { api: targetApi },
configs: targetConfigs
} = targetRole;
const accounts = await Promise.all(
keyringPairs.map(async ({ address, meta }) => {
const sourceAddress = encodeAddress(address, sourceConfigs.ss58Format);
const toDerive = {
ss58Format: targetConfigs.ss58Format,
address: sourceAddress || '',
bridgeId: getBridgeId(targetApi, sourceChain)
};
const { data } = await sourceApi.query.system.account(sourceAddress);
const sourceBalance = formatBalanceAddress(data, sourceApi);
const companionAddress = getDeriveAccount(toDerive);
const { data: dataCompanion } = await targetApi.query.system.account(companionAddress);
const targetBalance = formatBalanceAddress(dataCompanion, targetApi);
const name = (meta.name as string).toLocaleUpperCase();
return {
account: { address: sourceAddress, balance: sourceBalance, name },
companionAccount: { address: companionAddress, balance: targetBalance, name }
};
})
);
return accounts;
};
const sourceAddresses = await getAccountInformation(sourceChainDetails, targetChainDetails);
const targetAddresses = await getAccountInformation(targetChainDetails, sourceChainDetails);
dispatchAccount(
AccountActionCreators.setDisplaySenderAccounts({
[sourceChainDetails.chain]: sourceAddresses,
[targetChainDetails.chain]: targetAddresses
})
);
},
[keyringPairs, keyringPairsReady, sourceChainDetails, targetChainDetails]
);
return { createType, stateCall, internalTransfer, updateSenderAccountsInformation };
}