@polkadot/util#BN TypeScript Examples
The following examples show how to use
@polkadot/util#BN.
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: Balance.ts From gear-js with GNU General Public License v3.0 | 6 votes |
transferFromAlice(to: string, value: number | BN, eventsCallback?: (event: any, data: any) => void): Promise<any> {
return new Promise(async (resolve, reject) => {
try {
const unsub = await this.api.tx.balances
.transfer(to, value)
.signAndSend(await GearKeyring.fromSuri('//Alice', 'Alice default'), ({ events }) => {
events.forEach(({ event: { data, method } }) => {
if (eventsCallback) {
eventsCallback(method, data);
}
if (method === 'Transfer') {
unsub();
resolve(0);
}
});
});
} catch (error) {
reject(new TransactionError(error.message));
}
});
}
Example #2
Source File: test-assets-pallet.ts From moonbeam with GNU General Public License v3.0 | 6 votes |
describeDevMoonbeam("Pallet Assets Pallet - assets transfer", (context) => {
let sudoAccount, assetId;
before("Test querying asset", async () => {
const keyring = new Keyring({ type: "ethereum" });
sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
// We need to mint units with sudo.setStorage, as we dont have xcm mocker yet
// And we need relay tokens for issuing a transaction to be executed in the relay
const balance = context.polkadotApi.createType("Balance", 100000000000000);
const assetBalance = context.polkadotApi.createType("PalletAssetsAssetAccount", {
balance: balance,
});
assetId = context.polkadotApi.createType(
"u128",
new BN("42259045809535163221576417993425387648")
);
const assetDetails = context.polkadotApi.createType("PalletAssetsAssetDetails", {
supply: balance,
});
await mockAssetBalance(context, assetBalance, assetDetails, sudoAccount, assetId, ALITH);
await createBlockWithExtrinsic(
context,
sudoAccount,
context.polkadotApi.tx.assets.transfer(assetId, BALTATHAR, 1000)
);
});
it("should query asset balance", async function () {
// Baltathar balance is 1000
let baltatharBalance = (await context.polkadotApi.query.assets.account(
assetId,
BALTATHAR
)) as any;
expect(baltatharBalance.unwrap()["balance"].eq(new BN(1000))).to.equal(true);
});
});
Example #3
Source File: Balance.ts From gear-js with GNU General Public License v3.0 | 6 votes |
transferBalance(
keyring: KeyringPair,
to: string,
value: number | BN,
eventsCallback?: (event: any, data: any) => void,
): Promise<any> {
return new Promise(async (resolve, reject) => {
try {
const unsub = await this.api.tx.balances.transfer(to, value).signAndSend(keyring, ({ events, status }) => {
events.forEach(({ event: { data, method } }) => {
if (eventsCallback) {
eventsCallback(method, data);
}
if (method === 'Transfer') {
unsub();
resolve(0);
}
});
});
} catch (error) {
reject(new TransactionError(error.message));
}
});
}
Example #4
Source File: blockTime.ts From contracts-ui with GNU General Public License v3.0 | 6 votes |
export function blockTimeMs(a: OrFalsy<ApiPromise>): BN {
return (a?.consts.babe?.expectedBlockTime || // Babe
// POW, eg. Kulupu
a?.consts.difficulty?.targetBlockTime ||
// Check against threshold to determine value validity
(a?.consts.timestamp?.minimumPeriod.gte(THRESHOLD)
? // Default minimum period config
a.consts.timestamp.minimumPeriod.mul(BN_TWO)
: a?.query.parachainSystem
? // default guess for a parachain
DEFAULT_TIME.mul(BN_TWO)
: // default guess for others
DEFAULT_TIME)) as BN;
}
Example #5
Source File: test-xcm-para.ts From moonbeam with GNU General Public License v3.0 | 6 votes |
async function registerAssetToParachain(
parachainApi: ApiPromise,
sudoKeyring: KeyringPair,
assetLocation: SourceLocation = sourceLocationRelay,
assetMetadata: AssetMetadata = relayAssetMetadata
) {
const { events: eventsRegister } = await createBlockWithExtrinsicParachain(
parachainApi,
sudoKeyring,
parachainApi.tx.sudo.sudo(
parachainApi.tx.assetManager.registerAsset(assetLocation, assetMetadata, new BN(1), true)
)
);
let assetId: string;
// Look for assetId in events
eventsRegister.forEach((e) => {
let ev = e.toHuman();
if (ev.section === "assetManager") {
assetId = ev.data[0];
}
});
if (!assetId) {
await new Promise((res) => setTimeout(res, 20000));
}
assetId = assetId.replace(/,/g, "");
// setAssetUnitsPerSecond
const { events } = await createBlockWithExtrinsicParachain(
parachainApi,
sudoKeyring,
parachainApi.tx.sudo.sudo(parachainApi.tx.assetManager.setAssetUnitsPerSecond(assetLocation, 0))
);
return { events, assetId };
}
Example #6
Source File: gear.ts From gear-js with GNU General Public License v3.0 | 5 votes |
accountBalance: BN;
Example #7
Source File: blockTime.ts From contracts-ui with GNU General Public License v3.0 | 5 votes |
DEFAULT_TIME = new BN(6_000)
Example #8
Source File: test-assets-sufficients.ts From moonbeam with GNU General Public License v3.0 | 5 votes |
relayAssetMetadata: AssetMetadata = {
name: "DOT",
symbol: "DOT",
decimals: new BN(12),
isFrozen: false,
}
Example #9
Source File: useEstimatedFeePayload.ts From parity-bridges-ui with GNU General Public License v3.0 | 4 votes |
useEstimatedFeePayload = (
transactionState: TransactionState,
dispatchTransaction: Dispatch<TransactionsActionType>
) => {
const { createType, stateCall } = useApiCallsContext();
const laneId = useLaneId();
const sourceTargetDetails = useSourceTarget();
const {
sourceChainDetails: {
chain: sourceChain,
apiConnection: { api: sourceApi }
},
targetChainDetails: {
apiConnection: { api: targetApi },
chain: targetChain
}
} = sourceTargetDetails;
const { account, senderAccountBalance, senderCompanionAccountBalance } = useAccountContext();
const { action, isBridged } = useGUIContext();
const { estimatedFeeMethodName } = getSubstrateDynamicNames(targetChain);
const previousPayloadEstimatedFeeLoading = usePrevious(transactionState.payloadEstimatedFeeLoading);
const { bridgedMessages } = getSubstrateDynamicNames(targetChain);
const dispatch = useCallback(
(error: string | null, data: PayloadEstimatedFee | null, loading: boolean) =>
dispatchTransaction(
TransactionActionCreators.setPayloadEstimatedFee({
payloadEstimatedFeeError: error,
payloadEstimatedFee: data,
payloadEstimatedFeeLoading: loading,
sourceTargetDetails,
createType,
isBridged,
senderAccountBalance,
senderCompanionAccountBalance,
chainDecimals: targetApi.registry.chainDecimals[0]
})
),
[
createType,
dispatchTransaction,
isBridged,
senderAccountBalance,
senderCompanionAccountBalance,
sourceTargetDetails,
targetApi.registry.chainDecimals
]
);
const calculateFeeAndPayload = useCallback(
async (currentTransactionState: TransactionState) => {
if (currentTransactionState.action === TransactionTypes.INTERNAL_TRANSFER) {
const { estimatedFee, weight } = await getFeeAndWeightForInternals({
api: sourceApi,
transactionState: currentTransactionState
});
const payload = {
sourceAccount: currentTransactionState.senderAccount,
transferAmount: currentTransactionState.transferAmount!.toNumber(),
receiverAddress: currentTransactionState.receiverAddress,
weight
};
return { estimatedSourceFee: estimatedFee, payload };
}
const { call, weight } = await getTransactionCallWeight({
action,
account,
targetApi,
transactionState: currentTransactionState
});
if (!call || !weight) {
return emptyData;
}
const callToCompact = currentTransactionState.action === TransactionTypes.CUSTOM ? call : call.slice(2);
const payload = {
call: compactAddLength(callToCompact),
origin: {
SourceAccount: account!.addressRaw
},
dispatch_fee_payment: currentTransactionState.payFee,
spec_version: targetApi.consts.system.version.specVersion.toNumber(),
weight
};
const payloadType = createType(sourceChain as keyof InterfaceTypes, 'OutboundPayload', payload);
logger.info(`OutboundPayload: ${JSON.stringify(payload)}`);
logger.info(`OutboundPayload.toHex(): ${payloadType.toHex()}`);
const messageFeeType = createType(sourceChain as keyof InterfaceTypes, 'MessageFeeData', {
lane_id: laneId,
payload: payloadType.toHex()
});
// estimatedFeeMessageDelivery
const estimatedFeeCall = await stateCall(sourceChain, estimatedFeeMethodName, messageFeeType.toHex());
const estimatedFeeType = createType(sourceChain as keyof InterfaceTypes, 'Option<Balance>', estimatedFeeCall);
const estimatedFeeMessageDelivery = estimatedFeeType.toString();
// estimatedFeeBridgeCall
const bridgeMessage = sourceApi.tx[bridgedMessages].sendMessage(laneId, payload, estimatedFeeCall);
const submitMessageTransactionFee = await sourceApi.rpc.payment.queryFeeDetails(bridgeMessage.toHex());
const estimatedFeeBridgeCallBalance = (submitMessageTransactionFee as FeeDetails).inclusionFee.unwrap()
.adjustedWeightFee;
const estimatedFeeBridgeCall = estimatedFeeBridgeCallBalance.toString();
// estimatedSourceFee calculation based on the sum of estimatedFeeMessageDelivery + estimatedFeeBridgeCallBalance
const estimatedSourceFeeBN = new BN(estimatedFeeMessageDelivery).add(estimatedFeeBridgeCallBalance.toBn());
const estimatedSourceFee = estimatedSourceFeeBN.toString();
// estimatedTargetFee
const targetFeeDetails = await targetApi.rpc.payment.queryFeeDetails(u8aToHex(call));
const estimatedTargetFee = (targetFeeDetails as FeeDetails).inclusionFee.unwrap().adjustedWeightFee.toString();
return {
estimatedSourceFee,
estimatedFeeMessageDelivery,
estimatedFeeBridgeCall,
estimatedTargetFee,
payload
};
},
[
account,
action,
bridgedMessages,
createType,
estimatedFeeMethodName,
laneId,
sourceApi,
sourceChain,
stateCall,
targetApi
]
);
useEffect(() => {
const { shouldEvaluatePayloadEstimatedFee, payloadEstimatedFeeLoading } = transactionState;
if (shouldEvaluatePayloadEstimatedFee && payloadEstimatedFeeLoading) {
logger.info(
'Transaction information changed while estimated fee is being calculating. Batching the new calculation.'
);
dispatchTransaction(TransactionActionCreators.setBatchedEvaluationPayloadEstimatedFee(transactionState));
}
if (shouldEvaluatePayloadEstimatedFee && !payloadEstimatedFeeLoading) {
genericCall({
//@ts-ignore
call: () => calculateFeeAndPayload(transactionState),
dispatch,
emptyData
});
}
}, [calculateFeeAndPayload, dispatch, dispatchTransaction, transactionState]);
useEffect(() => {
const { batchedTransactionState, payloadEstimatedFeeLoading } = transactionState;
if (
previousPayloadEstimatedFeeLoading &&
!payloadEstimatedFeeLoading &&
batchedTransactionState &&
senderAccountBalance &&
senderCompanionAccountBalance
) {
genericCall({
//@ts-ignore
call: () => calculateFeeAndPayload(batchedTransactionState),
dispatch,
emptyData
});
dispatchTransaction(TransactionActionCreators.setBatchedEvaluationPayloadEstimatedFee(null));
}
}, [
account,
calculateFeeAndPayload,
dispatch,
dispatchTransaction,
previousPayloadEstimatedFeeLoading,
senderAccountBalance,
senderCompanionAccountBalance,
transactionState
]);
}
Example #10
Source File: Transfer.tsx From subscan-multisig-react with Apache License 2.0 | 4 votes |
// eslint-disable-next-line complexity
function Transfer({
className = '',
onClose,
onTxSuccess,
recipientId: propRecipientId,
senderId: propSenderId,
}: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { multisigAccount } = useMultisig();
const [amount, setAmount] = useState<BN | undefined>(BN_ZERO);
const [hasAvailable] = useState(true);
const [isProtected, setIsProtected] = useState(true);
const [isAll, setIsAll] = useState(false);
const [[maxTransfer, noFees], setMaxTransfer] = useState<[BN | null, boolean]>([null, false]);
const [recipientId, setRecipientId] = useState<string | null>(null);
const [senderId, setSenderId] = useState<string | null>(null);
const [[, recipientPhish], setPhishing] = useState<[string | null, string | null]>([null, null]);
const balances = useCall<DeriveBalancesAll>(api.derive.balances?.all, [propSenderId || senderId]);
const accountInfo = useCall<AccountInfoWithProviders | AccountInfoWithRefCount>(api.query.system.account, [
propSenderId || senderId,
]);
const [multisigExtrinsic, setMultisigExtrinsic] = useState<SubmittableExtrinsic<'promise'> | null>(null);
const [accountId, setAccountId] = useState<string | null>(null);
const isExtensionAccount = useIsInjected();
const [reserveAmount, setReserveAmount] = useState(0);
const options = useMemo<KeyringSectionOption[]>(
() =>
((multisigAccount?.meta?.addressPair as AddressPair[]) ?? []).map(({ address, ...others }) => ({
...others,
value: address,
key: address,
})),
[multisigAccount?.meta]
);
const [optionsAll, setOptionsAll] = useState<Record<string, Option[]>>({
account: [],
all: [],
});
const [depositBase, depositFactor] = useMemo(() => {
return [Number(api?.consts.multisig.depositBase.toJSON()), Number(api?.consts.multisig.depositFactor.toJSON())];
}, [api]);
const [chainDecimal, chainToken] = useMemo(() => {
return [api?.registry.chainDecimals[0], api?.registry.chainTokens[0]];
}, [api]);
const createMultiItem = useCallback(
(option: Option): Option[] => {
if (option.value === multisigAccount?.address) {
return options.map((opt) => createItem(opt));
}
return [];
},
[multisigAccount?.address, options]
);
useEffect(() => {
const subscription = keyring.keyringOption.optionsSubject.subscribe((all) => {
const optAll = Object.entries(all).reduce(
(
result: Record<string, (Option | React.ReactNode)[]>,
[type, value]
): Record<string, (Option | React.ReactNode)[]> => {
result[type] = flatten(
value.map((option): Option | React.ReactNode =>
option.value === null
? createHeader(option)
: createMultiItem(option as Option).filter((item) => isExtensionAccount(item.value))
)
);
return result;
},
{}
);
setOptionsAll(optAll as Record<string, Option[]>);
});
return () => subscription.unsubscribe();
}, [createMultiItem, isExtensionAccount]);
// eslint-disable-next-line complexity
useEffect((): void => {
const fromId = propSenderId || (senderId as string);
const toId = propRecipientId || (recipientId as string);
if (balances && balances.accountId?.eq(fromId) && fromId && toId && isFunction(api.rpc.payment?.queryInfo)) {
setTimeout((): void => {
try {
api.tx.balances
?.transfer(toId, balances.availableBalance)
.paymentInfo(fromId)
.then(({ partialFee }): void => {
// eslint-disable-next-line no-magic-numbers
const adjFee = partialFee.muln(110).div(BN_HUNDRED);
const tempMaxTransfer = balances.availableBalance.sub(adjFee);
setMaxTransfer(
tempMaxTransfer.gt(api.consts.balances?.existentialDeposit as unknown as BN)
? [tempMaxTransfer, false]
: [null, true]
);
})
.catch(console.error);
} catch (error) {
console.error((error as Error).message);
}
}, 0);
} else {
setMaxTransfer([null, false]);
}
}, [api, balances, propRecipientId, propSenderId, recipientId, senderId]);
useEffect((): void => {
checkPhishing(propSenderId || senderId, propRecipientId || recipientId)
.then(setPhishing)
.catch(console.error);
}, [propRecipientId, propSenderId, recipientId, senderId]);
const noReference = accountInfo
? isRefcount(accountInfo)
? accountInfo.refcount.isZero()
: accountInfo.consumers.isZero()
: true;
const canToggleAll =
!isProtected && balances && balances.accountId?.eq(propSenderId || senderId) && maxTransfer && noReference;
useEffect(() => {
// eslint-disable-next-line complexity
(async () => {
const fn =
canToggleAll && isAll && isFunction(api.tx.balances?.transferAll)
? api.tx.balances?.transferAll
: isProtected
? api.tx.balances?.transferKeepAlive
: api.tx.balances?.transfer;
if (!fn || !propSenderId) {
setMultisigExtrinsic(null);
return;
}
const params =
canToggleAll && isAll && isFunction(api.tx.balances?.transferAll)
? [{ Id: recipientId }, amount]
: isProtected
? [{ Id: recipientId }, amount]
: [{ Id: recipientId }, amount];
const ext = fn(...params);
// eslint-disable-next-line no-console
// console.log('amount', amount?.toString());
const ARG_LENGTH = 6;
const info = await api?.query.multisig.multisigs(propSenderId, ext?.method.hash);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const timepoint = (info as any).isSome ? (info as any)?.unwrap().when : null;
const { threshold, who } = extractExternal(propSenderId);
const others: string[] = who.filter((item) => item !== accountId);
const { weight } = (await ext?.paymentInfo(propSenderId)) || { weight: 0 };
const module = api?.tx.multisig;
const argsLength = module?.asMulti.meta.args.length || 0;
const generalParams = [threshold, others, timepoint];
const args =
argsLength === ARG_LENGTH ? [...generalParams, ext.method.toHex(), true, weight] : [...generalParams, ext];
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const multiTx = module?.asMulti(...args);
// eslint-disable-next-line no-console
// console.log('hexCallData', ext.method.toHex());
setMultisigExtrinsic(multiTx);
// Estimate reserve amount
try {
if (chainDecimal) {
setReserveAmount(
// eslint-disable-next-line no-magic-numbers
(depositBase * 2 + depositFactor * threshold + (depositFactor * (ext.method.toHex().length + 31)) / 32) /
Math.pow(10, chainDecimal)
);
}
} catch (err) {
setReserveAmount(0);
}
})();
}, [
canToggleAll,
isAll,
api,
isProtected,
amount,
recipientId,
propSenderId,
accountId,
chainDecimal,
depositBase,
depositFactor,
]);
return (
<Modal className="app--accounts-Modal" header={t<string>('Send funds')} onClose={onClose} size="large">
<Modal.Content>
<div className={className}>
<Modal.Columns
hint={t<string>('The transferred balance will be subtracted (along with fees) from the sender account.')}
>
<PureInputAddress
label={t<string>('using the selected account')}
labelExtra={<BalanceFree label={<label>{t<string>('free balance')}</label>} params={accountId} />}
onChange={setAccountId}
optionsAll={optionsAll}
type="account"
/>
</Modal.Columns>
<Modal.Columns
hint={t<string>('The transferred balance will be subtracted (along with fees) from the sender account.')}
>
<InputAddress
defaultValue={propSenderId}
help={t<string>('The account you will send funds from.')}
isDisabled={!!propSenderId}
label={t<string>('send from account')}
labelExtra={<Available label={t<string>('transferrable')} params={propSenderId || senderId} />}
onChange={setSenderId}
type="account"
/>
</Modal.Columns>
<Modal.Columns
hint={t<string>(
'The beneficiary will have access to the transferred fees when the transaction is included in a block.'
)}
>
<InputAddress
defaultValue={propRecipientId}
help={t<string>('Select a contact or paste the address you want to send funds to.')}
isDisabled={!!propRecipientId}
label={t<string>('send to address')}
labelExtra={<Available label={t<string>('transferrable')} params={propRecipientId || recipientId} />}
onChange={setRecipientId}
type="allPlus"
/>
{recipientPhish && (
<MarkError
content={t<string>('The recipient is associated with a known phishing site on {{url}}', {
replace: { url: recipientPhish },
})}
/>
)}
</Modal.Columns>
<Modal.Columns
hint={t<string>(
'If the recipient account is new, the balance needs to be more than the existential deposit. Likewise if the sending account balance drops below the same value, the account will be removed from the state.'
)}
>
{canToggleAll && isAll ? (
<InputBalance
autoFocus
defaultValue={maxTransfer}
help={t<string>('The full account balance to be transferred, minus the transaction fees')}
isDisabled
key={maxTransfer?.toString()}
label={t<string>('transferrable minus fees')}
/>
) : (
<>
<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}
isZeroable
label={t<string>('amount')}
maxValue={maxTransfer}
onChange={setAmount}
/>
<InputBalance
defaultValue={api.consts.balances?.existentialDeposit}
help={t<string>('The minimum amount that an account should have to be deemed active')}
isDisabled
label={t<string>('existential deposit')}
/>
</>
)}
</Modal.Columns>
<Modal.Columns
hint={t('With the keep-alive option set, the account is protected against removal due to low balances.')}
>
{isFunction(api.tx.balances?.transferKeepAlive) && (
<Toggle
className="typeToggle"
label={
isProtected
? t<string>('Transfer with account keep-alive checks')
: t<string>('Normal transfer without keep-alive checks')
}
onChange={setIsProtected}
value={isProtected}
/>
)}
{canToggleAll && (
<Toggle
className="typeToggle"
label={t<string>('Transfer the full account balance, reap the sender')}
onChange={setIsAll}
value={isAll}
/>
)}
{!isProtected && !noReference && (
<MarkWarning
content={t<string>(
'There is an existing reference count on the sender account. As such the account cannot be reaped from the state.'
)}
/>
)}
{noFees && (
<MarkWarning
content={t<string>(
'The transaction, after application of the transfer fees, will drop the available balance below the existential deposit. As such the transfer will fail. The account needs more free funds to cover the transaction fees.'
)}
/>
)}
</Modal.Columns>
</div>
</Modal.Content>
<div className="flex items-center justify-between px-5">
<Text style={{ color: 'rgba(78,78,78,0.6)', marginLeft: '20px' }}>
{t('multisig.estimate_reserve')} {reserveAmount} {chainToken}
</Text>
<Modal.Actions onCancel={onClose}>
<TxButton
// accountId={propSenderId || senderId}
accountId={accountId}
icon="paper-plane"
isDisabled={!hasAvailable || !(propRecipientId || recipientId) || !amount || !!recipientPhish}
label={t<string>('Make Transfer')}
onStart={onClose}
extrinsic={multisigExtrinsic}
onSuccess={onTxSuccess}
// params={
// canToggleAll && isAll
// ? isFunction(api.tx.balances?.transferAll)
// ? [propRecipientId || recipientId, false]
// : [propRecipientId || recipientId, maxTransfer]
// : [propRecipientId || recipientId, amount]
// }
// tx={
// canToggleAll && isAll && isFunction(api.tx.balances?.transferAll)
// ? api.tx.balances?.transferAll
// : isProtected
// ? api.tx.balances?.transferKeepAlive
// : api.tx.balances?.transfer
// }
/>
</Modal.Actions>
</div>
</Modal>
);
}
Example #11
Source File: test-assets-sufficients.ts From moonbeam with GNU General Public License v3.0 | 4 votes |
describeDevMoonbeam(
"Pallet Assets - Sufficient tests: is_sufficient to true",
(context) => {
let sudoAccount, assetId;
before("Setup contract and mock balance", async () => {
const keyring = new Keyring({ type: "ethereum" });
sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
// We need to mint units with sudo.setStorage, as we dont have xcm mocker yet
// And we need relay tokens for issuing a transaction to be executed in the relay
const balance = new BN("100000000000000");
const assetBalance = context.polkadotApi.createType("PalletAssetsAssetAccount", {
balance: balance,
});
assetId = context.polkadotApi.createType(
"u128",
new BN("42259045809535163221576417993425387648")
);
const assetDetails = context.polkadotApi.createType("PalletAssetsAssetDetails", {
supply: balance,
isSufficient: true,
minBalance: 1,
});
await mockAssetBalance(
context,
assetBalance,
assetDetails,
sudoAccount,
assetId,
ALITH,
true
);
await context.createBlock();
let alithBalance = (await context.polkadotApi.query.assets.account(assetId, ALITH)) as any;
expect(alithBalance.unwrap()["balance"].eq(new BN(100000000000000))).to.equal(true);
});
it("Send MOVR and assets to an account, then drain assets, then MOVR", async function () {
// We are going to use a fresh account here, since we mocked the asset balance
const keyring = new Keyring({ type: "ethereum" });
const alith = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
const seed = randomAsHex(32);
const transferAmount = new BN("10000000000000");
let freshAccount = await keyring.addFromUri(seed, null, "ethereum");
// We transfer Assets to freshAccount, which should increase sufficients
await context.polkadotApi.tx.assets
.transfer(assetId, freshAccount.address, transferAmount)
.signAndSend(alith);
await context.createBlock();
let freshAccountBalance = (await context.polkadotApi.query.assets.account(
assetId,
freshAccount.address
)) as any;
expect(freshAccountBalance.unwrap()["balance"].eq(new BN(10000000000000))).to.equal(true);
expect(
(
(await context.polkadotApi.query.system.account(freshAccount.address)) as any
).sufficients.toBigInt()
).to.eq(1n);
// Providers should still be 0
expect(
(
(await context.polkadotApi.query.system.account(freshAccount.address)) as any
).providers.toBigInt()
).to.eq(0n);
// We transfer a good amount to be able to pay for fees
await context.polkadotApi.tx.balances
.transfer(freshAccount.address, 1n * GLMR)
.signAndSend(alith);
await context.createBlock();
expect(
(
(await context.polkadotApi.query.system.account(freshAccount.address)) as any
).sufficients.toBigInt()
).to.eq(1n);
// Providers should now be 1
expect(
(
(await context.polkadotApi.query.system.account(freshAccount.address)) as any
).providers.toBigInt()
).to.eq(1n);
// Let's drain assets
await context.polkadotApi.tx.assets
.transfer(assetId, BALTATHAR, transferAmount)
.signAndSend(freshAccount);
await context.createBlock();
// Lets drain native token
// First calculate fee
// Then grab balance of freshAccount
// Then we just transfer out balance of freshAccount - fee
const fee = (
await context.polkadotApi.tx.balances.transfer(ALITH, 1n * GLMR).paymentInfo(freshAccount)
).partialFee as any;
let freshAccountBalanceNativeToken = (
(await context.polkadotApi.query.system.account(freshAccount.address)) as any
).data.free.toBigInt();
await context.polkadotApi.tx.balances
.transfer(BALTATHAR, freshAccountBalanceNativeToken - BigInt(fee))
.signAndSend(freshAccount);
await context.createBlock();
freshAccountBalance = (await context.polkadotApi.query.assets.account(
assetId,
freshAccount.address
)) as any;
expect(freshAccountBalance.isNone).to.equal(true);
// Sufficients should go to 0
expect(
(
(await context.polkadotApi.query.system.account(freshAccount.address)) as any
).sufficients.toBigInt()
).to.eq(0n);
// Providers should be 1
expect(
(
(await context.polkadotApi.query.system.account(freshAccount.address)) as any
).providers.toBigInt()
).to.eq(1n);
// Nonce should be 1
expect(
(
(await context.polkadotApi.query.system.account(freshAccount.address)) as any
).providers.toBigInt()
).to.eq(1n);
// But balance of MOVR should be 0
expect(
(
(await context.polkadotApi.query.system.account(freshAccount.address)) as any
).data.free.toBigInt()
).to.eq(0n);
});
},
"Legacy",
true
);