@polkadot/util#BN_MILLION TypeScript Examples
The following examples show how to use
@polkadot/util#BN_MILLION.
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: useInflation.ts From crust-apps with Apache License 2.0 | 6 votes |
export function calcInflation (api: ApiPromise, totalStaked: BN, totalIssuance: BN): Inflation {
const { falloff, idealStake, maxInflation, minInflation } = getInflationParams(api);
const stakedFraction = totalStaked.isZero() || totalIssuance.isZero()
? 0
: totalStaked.mul(BN_MILLION).div(totalIssuance).toNumber() / BN_MILLION.toNumber();
const idealInterest = maxInflation / idealStake;
const inflation = 100 * (minInflation + (
stakedFraction <= idealStake
? (stakedFraction * (idealInterest - (minInflation / idealStake)))
: (((idealInterest * idealStake) - minInflation) * Math.pow(2, (idealStake - stakedFraction) / falloff))
));
return {
inflation,
stakedReturn: stakedFraction
? (inflation / stakedFraction)
: 0
};
}
Example #2
Source File: useTreasury.ts From crust-apps with Apache License 2.0 | 6 votes |
export function useTreasury (): Result {
const { api } = useApi();
const [result, setResult] = useState<Result>({
spendPeriod: api.consts.treasury
? api.consts.treasury.spendPeriod
: BN_ZERO
});
const treasuryBalance = useCall<DeriveBalancesAccount>(api.derive.balances.account, [TREASURY_ACCOUNT]);
useEffect(() => {
if (!api.consts.treasury) {
return;
}
setResult(({ spendPeriod }) => ({
burn: treasuryBalance?.freeBalance.gtn(0) && !api.consts.treasury.burn.isZero()
? api.consts.treasury.burn.mul(treasuryBalance.freeBalance).div(BN_MILLION)
: BN_ZERO,
spendPeriod,
value: treasuryBalance?.freeBalance.gtn(0)
? treasuryBalance.freeBalance
: undefined
}));
}, [api, treasuryBalance]);
return result;
}
Example #3
Source File: gov.ts From sdk with Apache License 2.0 | 6 votes |
/**
* Query overview of treasury and spend proposals.
*/
async function getTreasuryOverview(api: ApiPromise) {
const [bounties, proposals, balance] = await Promise.all([
api.derive.bounties?.bounties(),
api.derive.treasury.proposals(),
api.derive.balances.account(TREASURY_ACCOUNT as AccountId),
]);
const pendingBounties = bounties.reduce(
(total, { bounty: { status, value } }) => total.iadd(status.isApproved ? value : BN_ZERO),
new BN(0)
);
const pendingProposals = proposals.approvals.reduce((total, { proposal: { value } }) => total.iadd(value), new BN(0));
const burn =
balance.freeBalance.gt(BN_ZERO) && !(api.consts.treasury.burn as any).isZero()
? (api.consts.treasury.burn as any).mul(balance.freeBalance).div(BN_MILLION)
: BN_ZERO;
const res: any = {
...proposals,
};
res["balance"] = balance.freeBalance.toString();
res["burn"] = burn.toString();
res["approved"] = pendingProposals.toString();
res["spendable"] = balance.freeBalance
.sub(pendingBounties)
.sub(pendingProposals)
.toString();
res.proposals.forEach((e: any) => {
if (e.council.length) {
e.council = e.council.map((i: any) => ({
...i,
proposal: _transfromProposalMeta(i.proposal),
}));
}
});
return res;
}
Example #4
Source File: useInflation.ts From subscan-multisig-react with Apache License 2.0 | 6 votes |
function calcInflation(api: ApiPromise, totalStaked: BN, totalIssuance: BN, numAuctions: BN): Inflation {
const { auctionAdjust, auctionMax, falloff, maxInflation, minInflation, stakeTarget } = getInflationParams(api);
const stakedFraction =
totalStaked.isZero() || totalIssuance.isZero()
? 0
: totalStaked.mul(BN_MILLION).div(totalIssuance).toNumber() / BN_MILLION.toNumber();
const idealStake = stakeTarget - Math.min(auctionMax, numAuctions.toNumber()) * auctionAdjust;
const idealInterest = maxInflation / idealStake;
const inflation =
100 *
(minInflation +
(stakedFraction <= idealStake
? stakedFraction * (idealInterest - minInflation / idealStake)
: (idealInterest * idealStake - minInflation) * Math.pow(2, (idealStake - stakedFraction) / falloff)));
return {
idealInterest,
idealStake,
inflation,
stakedFraction,
stakedReturn: stakedFraction ? inflation / stakedFraction : 0,
};
}
Example #5
Source File: useTreasury.ts From subscan-multisig-react with Apache License 2.0 | 6 votes |
export function useTreasury(): Result {
const { api } = useApi();
const [result, setResult] = useState<Result>({
spendPeriod: api.consts.treasury ? (api.consts.treasury.spendPeriod as unknown as BN) : BN_ZERO,
});
const treasuryBalance = useCall<DeriveBalancesAccount>(api.derive.balances?.account, [TREASURY_ACCOUNT]);
useEffect(() => {
if (!api.consts.treasury) {
return;
}
setResult(({ spendPeriod }) => ({
burn:
treasuryBalance?.freeBalance.gtn(0) && !(api.consts.treasury.burn as unknown as BN).isZero()
? (api.consts.treasury.burn as unknown as BN).mul(treasuryBalance.freeBalance).div(BN_MILLION)
: BN_ZERO,
spendPeriod,
value: treasuryBalance?.freeBalance.gtn(0) ? treasuryBalance.freeBalance : undefined,
}));
}, [api, treasuryBalance]);
return result;
}
Example #6
Source File: permillOf.ts From crust-apps with Apache License 2.0 | 5 votes |
export function permillOf (value: BN, perMill: BN): BN {
return value.mul(perMill).div(BN_MILLION);
}
Example #7
Source File: InputMegaGas.tsx From crust-apps with Apache License 2.0 | 5 votes |
function InputMegaGas ({ className, estimatedWeight, help, isCall, weight: { executionTime, isValid, megaGas, percentage, setIsEmpty, setMegaGas } }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const [withEstimate, setWithEstimate] = useState(true);
const estimatedMg = useMemo(
() => estimatedWeight
? estimatedWeight.div(BN_MILLION).iadd(BN_ONE)
: null,
[estimatedWeight]
);
useEffect((): void => {
withEstimate && estimatedMg && setMegaGas(estimatedMg);
}, [estimatedMg, setMegaGas, withEstimate]);
useEffect((): void => {
setIsEmpty(withEstimate && !!isCall);
}, [isCall, setIsEmpty, withEstimate]);
const isDisabled = !!estimatedMg && withEstimate;
return (
<div className={className}>
<InputNumber
defaultValue={estimatedMg && isDisabled ? estimatedMg.toString() : undefined}
help={help}
isDisabled={isDisabled}
isError={!isValid}
isZeroable={isCall}
label={
estimatedMg && (isCall ? !withEstimate : true)
? t<string>('max gas allowed (M, {{estimatedMg}} estimated)', { replace: { estimatedMg: estimatedMg.toString() } })
: t<string>('max gas allowed (M)')
}
onChange={isDisabled ? undefined : setMegaGas}
value={isDisabled ? undefined : ((isCall && withEstimate) ? BN_ZERO : megaGas)}
>
{(estimatedWeight || isCall) && (
<Toggle
isOverlay
label={
isCall
? t<string>('max read gas')
: t<string>('use estimated gas')
}
onChange={setWithEstimate}
value={withEstimate}
/>
)}
</InputNumber>
<div className='contracts--InputMegaGas-meter'>
{t<string>('{{executionTime}}s execution time', { replace: { executionTime: executionTime.toFixed(3) } })}{', '}
{t<string>('{{percentage}}% of block weight', { replace: { percentage: percentage.toFixed(2) } })}
</div>
</div>
);
}
Example #8
Source File: useWeight.ts From crust-apps with Apache License 2.0 | 5 votes |
export default function useWeight (): UseWeight {
const { api } = useApi();
const [blockTime] = useBlockTime();
const [megaGas, _setMegaGas] = useState<BN>(
(api.consts.system.blockWeights
? api.consts.system.blockWeights.maxBlock
: api.consts.system.maximumBlockWeight as Weight
).div(BN_MILLION).div(BN_TEN)
);
const [isEmpty, setIsEmpty] = useState(false);
const setMegaGas = useCallback(
(value?: BN | undefined) => _setMegaGas(value || (
(api.consts.system.blockWeights
? api.consts.system.blockWeights.maxBlock
: api.consts.system.maximumBlockWeight as Weight
).div(BN_MILLION).div(BN_TEN)
)),
[api]
);
return useMemo((): UseWeight => {
let executionTime = 0;
let percentage = 0;
let weight = BN_ZERO;
let isValid = false;
if (megaGas) {
weight = megaGas.mul(BN_MILLION);
executionTime = weight.muln(blockTime).div(
api.consts.system.blockWeights
? api.consts.system.blockWeights.maxBlock
: api.consts.system.maximumBlockWeight as Weight
).toNumber();
percentage = (executionTime / blockTime) * 100;
// execution is 2s of 6s blocks, i.e. 1/3
executionTime = executionTime / 3000;
isValid = !megaGas.isZero() && percentage < 65;
}
return {
executionTime,
isEmpty,
isValid: isEmpty || isValid,
megaGas: megaGas || BN_ZERO,
percentage,
setIsEmpty,
setMegaGas,
weight
};
}, [api, blockTime, isEmpty, megaGas, setIsEmpty, setMegaGas]);
}
Example #9
Source File: InputGas.tsx From contracts-ui with GNU General Public License v3.0 | 5 votes |
export function InputGas({
className,
defaultWeight,
estimatedWeight,
executionTime,
isActive,
isCall,
isValid,
megaGas,
percentage,
setIsActive,
setMegaGas,
weight,
withEstimate,
...props
}: Props) {
return (
<div className={classes(className)} {...props}>
<InputNumber
value={megaGas}
isDisabled={!isActive}
onChange={value => {
if (isActive) {
setMegaGas(value);
}
}}
placeholder="MGas"
/>
<Meter
accessory={
isActive ? (
<a
href="#"
onClick={e => {
e.preventDefault();
setIsActive(false);
}}
className="text-green-500"
>
{isCall
? `Use Estimated Gas (${(estimatedWeight || BN_ZERO)
.div(BN_MILLION)
.add(BN_ONE)
.toString()}M)`
: 'Use Maximum Query Gas'}
</a>
) : (
<>
{isCall ? 'Using Estimated Gas' : 'Using Maximum Query Gas'}
{' ยท '}
<a
href="#"
onClick={e => {
e.preventDefault();
setIsActive(true);
}}
className="text-green-500"
>
Use Custom
</a>
</>
)
}
label={`${
executionTime < 0.001 ? '<0.001' : executionTime.toFixed(3)
}s execution time (${percentage.toFixed(2)}% of block time)}`}
percentage={percentage}
withAccessory={withEstimate}
/>
</div>
);
}
Example #10
Source File: useWeight.ts From contracts-ui with GNU General Public License v3.0 | 5 votes |
function getEstimatedMegaGas(api: ApiPromise, estimatedWeight: OrFalsy<BN>, withBuffer = true): BN {
return (estimatedWeight || maximumBlockWeight(api)).div(BN_MILLION).addn(withBuffer ? 1 : 0);
}
Example #11
Source File: useWeight.ts From contracts-ui with GNU General Public License v3.0 | 5 votes |
function getDefaultMegaGas(api: OrFalsy<ApiPromise>, estimatedWeight?: OrFalsy<BN>): BN {
if (api && estimatedWeight) {
return getEstimatedMegaGas(api, estimatedWeight);
}
return maximumBlockWeight(api).div(BN_MILLION).div(BN_TEN);
}
Example #12
Source File: useWeight.ts From contracts-ui with GNU General Public License v3.0 | 5 votes |
useWeight = (estimatedWeight: OrFalsy<BN>): UseWeight => {
// const estimatedWeightRef = useRef(estimatedWeight);
const { api } = useApi();
const [blockTime] = useBlockTime();
const [megaGas, _setMegaGas] = useState<BN>(getDefaultMegaGas(api, estimatedWeight));
const [isActive, setIsActive] = useState(!!estimatedWeight);
const defaultWeight = useMemo((): BN => maximumBlockWeight(api), [api]);
const setMegaGas = useCallback(
(value?: BN | undefined) => {
_setMegaGas(value || getDefaultMegaGas(api, null));
},
[api]
);
useEffect((): void => {
if (!isActive) {
_setMegaGas(getDefaultMegaGas(api, estimatedWeight));
}
}, [api, estimatedWeight, isActive]);
return useMemo((): UseWeight => {
let executionTime = 0;
let percentage = 0;
let weight = BN_ZERO;
let isValid = false;
if (megaGas) {
weight = megaGas.mul(BN_MILLION);
executionTime = weight.muln(blockTime).div(maximumBlockWeight(api)).toNumber();
percentage = (executionTime / blockTime) * 100;
// execution is 2s of 6s blocks, i.e. 1/3
executionTime = executionTime / 3000;
isValid = !megaGas.isZero() && percentage < 65;
}
return {
defaultWeight,
estimatedWeight,
executionTime,
isActive,
isValid: !isActive || isValid,
megaGas: megaGas || BN_ZERO,
percentage,
setIsActive,
setMegaGas,
weight,
};
}, [api, blockTime, defaultWeight, estimatedWeight, isActive, megaGas, setIsActive, setMegaGas]);
}
Example #13
Source File: index.ts From sdk with Apache License 2.0 | 5 votes |
function _extractTargetsInfo(api: ApiPromise, electedDerive: DeriveStakingElected, waitingDerive: DeriveStakingWaiting, totalIssuance: BN, lastEraInfo: LastEra, historyDepth?: BN): Partial<SortedTargets> {
const [elected, nominators] = _extractSingleTarget(api, electedDerive, lastEraInfo, historyDepth);
const [waiting] = _extractSingleTarget(api, waitingDerive, lastEraInfo);
const activeTotals = elected
.filter(({ isActive }) => isActive)
.map(({ bondTotal }) => bondTotal)
.sort((a, b) => a.cmp(b));
const totalStaked = activeTotals.reduce((total: BN, value) => total.iadd(value), new BN(0));
const avgStaked = totalStaked.divn(activeTotals.length);
const inflation = _calcInflation(api, totalStaked, totalIssuance);
// add the explicit stakedReturn
!avgStaked.isZero() && elected.forEach((e): void => {
if (!e.skipRewards) {
e.stakedReturn = inflation.stakedReturn * avgStaked.mul(BN_MILLION).div(e.bondTotal).toNumber() / BN_MILLION.toNumber();
e.stakedReturnCmp = e.stakedReturn * (100 - e.commissionPer) / 100;
}
});
const minNominated = elected.reduce((min: BN, { minNominated }) => {
return min.isZero() || minNominated.lt(min)
? minNominated
: min;
}, BN_ZERO);
// all validators, calc median commission
const validators = sortValidators(arrayFlatten([elected, waiting]));
const commValues = validators.map(({ commissionPer }) => commissionPer).sort((a, b) => a - b);
const midIndex = Math.floor(commValues.length / 2);
const medianComm = commValues.length
? commValues.length % 2
? commValues[midIndex]
: (commValues[midIndex - 1] + commValues[midIndex]) / 2
: 0;
// ids
const electedIds = elected.map(({ key }) => key);
const waitingIds = waiting.map(({ key }) => key);
const validatorIds = arrayFlatten([electedIds, waitingIds]);
return {
avgStaked,
inflation,
lowStaked: activeTotals[0] || BN_ZERO,
medianComm,
minNominated,
nominators,
totalIssuance,
totalStaked,
validatorIds,
validators,
waitingIds
};
}
Example #14
Source File: index.tsx From crust-apps with Apache License 2.0 | 4 votes |
function PollApp ({ basePath, className }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const bestNumber = useBestNumber();
const [totalIssuance, totals] = useCallMulti<MultiResult>([
api.query.balances.totalIssuance,
api.query.poll.totals
], optMulti);
const [accountId, setAccountId] = useState<string | null>(null);
const [turnout, setTurnout] = useState<Turnout | null>(null);
const [opt10m, setOpt10m] = useState(false);
const [opt100m, setOpt100m] = useState(false);
const [opt1b, setOpt1b] = useState(false);
const [opt10b, setOpt10b] = useState(false);
const [progress, setProgress] = useState<BN[] | undefined>();
const itemsRef = useRef([{
isRoot: true,
name: 'poll',
text: t<string>('Denomination poll')
}]);
useEffect((): void => {
if (totalIssuance && totals) {
const max = bnMax(BN_ONE, ...totals);
setProgress(totals.map((total) => total.mul(BN_MILLION).div(max)));
api.query.poll.voteOf
.entries<ITuple<[Approvals, Balance]>>()
.then((entries): void => {
const voted = entries.reduce((voted: BN, [, [, balance]]) => voted.iadd(balance), new BN(0));
const percentage = voted.muln(10_000).div(totalIssuance).toNumber() / 100;
setTurnout({ percentage, voted });
})
.catch(console.log);
}
}, [api, totalIssuance, totals]);
if (!totals || !progress || !bestNumber) {
return (
<main className={className}>
<div className='pollContainer'>
<Spinner label={t<string>('Retrieving totals...')} />
</div>
</main>
);
}
const blocksLeft = (api.consts.poll.end as BlockNumber).sub(bestNumber);
const canVote = blocksLeft.gt(BN_ZERO);
const options: [string, string, boolean, (value: boolean) => void][] = [
[t('No change'), t('No change from the original 2017 sale definitions; will mean a total of 10 million DOT from genesis.'), opt10m, setOpt10m],
[t('Split of 10x'), t('Split of 10x from the original sale; will mean a total of 100 million DOT from genesis. Apparent DOT price would be 10x lower and apparent account balances 10x higher.'), opt100m, setOpt100m],
[t('Split of 100x'), t('Split of 100x from the original sale; will mean a total of 1 billion DOT from genesis. Apparent DOT price would be 100x lower and apparent account balances 100x higher.'), opt1b, setOpt1b],
[t('Split of 1000x'), t('Split of 1000x from the original sale; will mean a total of 10 billion DOT from genesis. Apparent DOT price would be 1000x lower and apparent account balances 1000x higher.'), opt10b, setOpt10b]
];
const hasValue = opt10m || opt100m || opt1b || opt10b;
/* eslint-disable react/jsx-max-props-per-line */
return (
<main className={className}>
<Tabs
basePath={basePath}
items={itemsRef.current}
/>
<div className='pollContainer'>
<div className='pollHeader'>
<h1>{t('denomination vote')}</h1>
<div className='pollBlocksRight'>
{turnout && (
<div>
<div>{t('{{balance}} voted', { replace: { balance: formatBalance(turnout.voted) } })}</div>
<div>{t('{{percentage}}% turnout', { replace: { percentage: turnout.percentage.toFixed(2) } })}</div>
</div>
)}
<div>
{canVote
? <BlockToTime value={blocksLeft} />
: t<string>('Completed')
}
<div>#{formatNumber(api.consts.poll.end as BlockNumber)}</div>
</div>
</div>
</div>
<article className='keepAlive'>
<p><Trans key='poll1'>The Polkadot DOT denomination vote: Seventy-two hours after the DOT token becomes transferable, the most popular option from this poll will decide the denomination used for the DOT token.</Trans></p>
<p><Trans key='poll2'>This is an <a href='https://en.wikipedia.org/wiki/Approval_voting' rel='noreferrer' target='_blank'>approval vote</a>. There are four options and you may select any combination of them. The most popular of the four will be selected as the final DOT denomination three days after DOT token transfers are enabled.</Trans></p>
<p><Trans key='poll3'>Please see the <a href='https://medium.com/polkadot-network/the-first-polkadot-vote-1fc1b8bd357b' rel='noreferrer' target='_blank'>Medium article </a> for more information</Trans></p>
{canVote && (
<p className='pollAll'><Trans key='poll4'><b>Please vote for any combination of options</b></Trans></p>
)}
<div className={`options ${canVote ? 'canVote' : ''}`}>
{options.map(([label, desc, value, onChange], index) =>
<Columar
is60
key={index}
>
<Columar.Column className='option'>
<div className='optionName'>{label}</div>
<div className='optionDesc'>{desc}</div>
{canVote && (
<Toggle
className='pollToggle'
isDisabled={!canVote}
label={
canVote
? value
? t<string>('Aye, I support this')
: t<string>('Nay, I do not support this')
: t<string>('Voting closed')
}
onChange={onChange}
value={canVote && value}
/>
)}
</Columar.Column>
<Columar.Column>
{totals[index].isZero()
? <div className='result' />
: (
<div className='result'>
<FormatBalance value={totals[index]} />
<Progress
isDisabled={!turnout}
total={turnout?.voted}
value={totals[index]}
/>
</div>
)
}
</Columar.Column>
</Columar>
)}
</div>
{canVote && (
<>
<InputAddress
label={t('vote using my account')}
onChange={setAccountId}
type='account'
/>
<Button.Group>
<TxButton
accountId={accountId}
icon='paper-plane'
isDisabled={!hasValue}
label={t('Vote')}
params={[[opt10m, opt100m, opt1b, opt10b]]}
tx={api.tx.poll.vote}
/>
</Button.Group>
</>
)}
</article>
<div className='pollActions'>
<ul>
<li>{t('Any combination of the four options may be approved of by the voter. There is no need to select only one option!')}</li>
<li>{t('Approving of all or none of the options is equivalent and will not affect the outcome of the poll.')}</li>
<li>{t('All voters may alter their votes any number of times prior to the close of the poll.')}</li>
<li>{t('Voting costs nothing other than the transaction fee and can be done from all accounts with a non-zero spendable balance.')}</li>
<li>{t('Locked funds (e.g. for staking) are counted.')}</li>
<li>{t('No discretionary lock-voting is in place; all DOT used to vote counts the same.')}</li>
<li>{t('Voting is made on a per-account basis; a single account must all vote the same way and cannot split its vote.')}</li>
<li>{t('This vote does not affect any economics of the Polkadot platform. Staking rewards, inflation, effective market capitalisation and the underlying balances of every account remain completely unchanged. It is "merely" about what units we use to denominate the balances into "DOT" for the purpose of display.')}</li>
</ul>
</div>
</div>
</main>
);
}
Example #15
Source File: ProposalCreate.tsx From crust-apps with Apache License 2.0 | 4 votes |
function Propose ({ className }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const [accountId, setAccountId] = useState<string | null>(null);
const [beneficiary, setBeneficiary] = useState<string | null>(null);
const [isOpen, toggleOpen] = useToggle();
const [value, setValue] = useState<BN | undefined>();
const hasValue = value?.gtn(0);
const bondPercentage = useMemo(
() => `${api.consts.treasury.proposalBond.mul(BN_HUNDRED).div(BN_MILLION).toNumber().toFixed(2)}%`,
[api]
);
return (
<>
{isOpen && (
<Modal
className={className}
header={t<string>('Submit treasury proposal')}
size='large'
>
<Modal.Content>
<Modal.Columns hint={t<string>('This account will make the proposal and be responsible for the bond.')}>
<InputAddress
help={t<string>('Select the account you wish to submit the proposal from.')}
label={t<string>('submit with account')}
onChange={setAccountId}
type='account'
withLabel
/>
</Modal.Columns>
<Modal.Columns hint={t<string>('The beneficiary will receive the full amount if the proposal passes.')}>
<InputAddress
help={t<string>('The account to which the proposed balance will be transferred if approved')}
label={t<string>('beneficiary')}
onChange={setBeneficiary}
type='allPlus'
/>
</Modal.Columns>
<Modal.Columns hint={
<>
<p>{t<string>('The value is the amount that is being asked for and that will be allocated to the beneficiary if the proposal is approved.')}</p>
<p>{t<string>('Of the beneficiary amount, at least {{bondPercentage}} would need to be put up as collateral. The maximum of this and the minimum bond will be used to secure the proposal, refundable if it passes.', { replace: { bondPercentage } })}</p>
</>
}>
<InputBalance
help={t<string>('The amount that will be allocated from the treasury pot')}
isError={!hasValue}
label={t<string>('value')}
onChange={setValue}
/>
<Static
help={t<string>('The on-chain percentage for the treasury')}
label={t<string>('proposal bond')}
>
{bondPercentage}
</Static>
<InputBalance
defaultValue={api.consts.treasury.proposalBondMinimum.toString()}
help={t<string>('The minimum amount that will be bonded')}
isDisabled
label={t<string>('minimum bond')}
/>
<MarkWarning content={t<string>('Be aware that once submitted the proposal will be put to a council vote. If the proposal is rejected due to a lack of info, invalid requirements or non-benefit to the network as a whole, the full bond posted (as describe above) will be lost.')} />
</Modal.Columns>
</Modal.Content>
<Modal.Actions onCancel={toggleOpen}>
<TxButton
accountId={accountId}
icon='plus'
isDisabled={!accountId || !hasValue}
label={t<string>('Submit proposal')}
onStart={toggleOpen}
params={[value, beneficiary]}
tx={api.tx.treasury.proposeSpend}
/>
</Modal.Actions>
</Modal>
)}
<Button
icon='plus'
label={t<string>('Submit proposal')}
onClick={toggleOpen}
/>
</>
);
}