Skip to content
This repository has been archived by the owner on Jul 15, 2022. It is now read-only.

LIVE-1292 Cover Polkadot existential deposit edge case (#1953) #1957

Merged
16 commits merged into from
May 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/bot-polkadot-silicium.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Bot 'Polkadot on Silicium'
on:
push:
branches:
- family/polkadot

jobs:
start-runner:
name: "start ec2 instance (Linux)"
if: ${{ always() }}
uses: ledgerhq/actions/.github/workflows/start-linux-runner.yml@main
secrets:
CI_BOT_TOKEN: ${{ secrets.CI_BOT_TOKEN }}

stop-runner:
name: "stop ec2 instance (Linux)"
needs: [start-runner, run-bot]
uses: ledgerhq/actions/.github/workflows/stop-linux-runner.yml@main
if: ${{ always() }}
with:
label: ${{ needs.start-runner.outputs.label }}
ec2-instance-id: ${{ needs.start-runner.outputs.ec2-instance-id }}
secrets:
CI_BOT_TOKEN: ${{ secrets.CI_BOT_TOKEN }}

run-bot:
needs: [start-runner]
runs-on: ${{ needs.start-runner.outputs.label }}
steps:
- name: prepare runner
run: |
sudo growpart /dev/nvme0n1 1
sudo resize2fs /dev/nvme0n1p1
- uses: actions/checkout@v2
- name: Retrieving coin apps
uses: actions/checkout@v2
with:
repository: LedgerHQ/coin-apps
token: ${{ secrets.PAT }}
path: coin-apps
- uses: actions/setup-node@master
with:
node-version: 14.x
- name: install yarn
run: npm i -g yarn
- name: pull docker image
run: docker pull ghcr.io/ledgerhq/speculos
- name: kill apt-get
run: sudo killall -w apt-get apt || echo OK
- name: Install linux deps
run: sudo apt-get install -y libusb-1.0-0-dev jq
- name: Install dependencies
run: |
yarn global add yalc
yarn --frozen-lockfile
yarn ci-setup-cli
- name: BOT
env:
SEED: ${{ secrets.SEED3 }}
BOT_REPORT_FOLDER: botreport
VERBOSE_FILE: botreport/logs.txt
GITHUB_SHA: ${GITHUB_SHA}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_RUN_ID: ${{ github.run_id }}
GITHUB_WORKFLOW: ${{ github.workflow }}
SLACK_API_TOKEN: ${{ secrets.SLACK_API_TOKEN }}
SLACK_CHANNEL: ci-dot-ll
BOT_FILTER_FAMILY: polkadot
run: mkdir botreport; COINAPPS=$PWD/coin-apps yarn ci-test-bot
timeout-minutes: 120
- name: Run coverage
if: failure() || success()
run: CODECOV_TOKEN=${{ secrets.CODECOV_TOKEN }} npx codecov
- name: upload logs
if: failure() || success()
uses: actions/upload-artifact@v1
with:
name: botreport
path: botreport/
2 changes: 1 addition & 1 deletion src/families/polkadot/cli-transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const options = [
{
name: "mode",
type: String,
desc: "mode of transaction: send, nominate, bond, claimReward",
desc: "mode of transaction: send, nominate, bond, claimReward, withdrawUnbonded",
},
{
name: "fees",
Expand Down
7 changes: 7 additions & 0 deletions src/families/polkadot/js-getTransactionStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
calculateAmount,
getMinimumAmountToBond,
getMinimumBalance,
EXISTENTIAL_DEPOSIT_RECOMMENDED_MARGIN,
} from "./logic";
import { isValidAddress } from "./address";
import { getCurrentPolkadotPreloadData } from "./preload";
Expand Down Expand Up @@ -78,6 +79,12 @@ const getSendTransactionStatus = async (
const leftover = a.spendableBalance.minus(totalSpent);

if (
a.spendableBalance.lte(
EXISTENTIAL_DEPOSIT.plus(EXISTENTIAL_DEPOSIT_RECOMMENDED_MARGIN)
)
) {
errors.amount = new NotEnoughBalance();
} else if (
minimumBalanceExistential.gt(0) &&
leftover.lt(minimumBalanceExistential) &&
leftover.gt(0)
Expand Down
20 changes: 10 additions & 10 deletions src/families/polkadot/js-signOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const MODE_TO_TYPE = {
};
const MODE_TO_PALLET_METHOD = {
send: "balances.transferKeepAlive",
sendMax: "balances.transfer",
bond: "staking.bond",
bondExtra: "staking.bondExtra",
unbond: "staking.unbond",
Expand All @@ -41,16 +42,15 @@ const MODE_TO_PALLET_METHOD = {
};

const getExtra = (type: string, account: Account, transaction: Transaction) => {
const extra = MODE_TO_PALLET_METHOD[transaction.mode]
? {
palletMethod:
MODE_TO_PALLET_METHOD[
transaction.mode === "bond" && !isFirstBond(account)
? "bondExtra"
: transaction.mode
],
}
: {};
const extra = {
palletMethod: MODE_TO_PALLET_METHOD[transaction.mode],
};

if (transaction.mode == "send" && transaction.useAllAmount) {
extra.palletMethod = MODE_TO_PALLET_METHOD["sendMax"];
} else if (transaction.mode === "bond" && !isFirstBond(account)) {
extra.palletMethod = MODE_TO_PALLET_METHOD["bondExtra"];
}

switch (type) {
case "OUT":
Expand Down
1 change: 1 addition & 0 deletions src/families/polkadot/logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Transaction } from "./types";
import { getCurrentPolkadotPreloadData } from "./preload";

export const EXISTENTIAL_DEPOSIT = new BigNumber(10000000000);
export const EXISTENTIAL_DEPOSIT_RECOMMENDED_MARGIN = new BigNumber(1000000000); // Polkadot recommended Existential Deposit error margin
export const MAX_NOMINATIONS = 16;
export const MAX_UNLOCKINGS = 32;
export const PRELOAD_MAX_AGE = 60 * 1000;
Expand Down
65 changes: 41 additions & 24 deletions src/families/polkadot/specs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ import {
canUnbond,
canNominate,
isFirstBond,
getMinimumAmountToBond,
hasMinimumBondBalance,
} from "../../families/polkadot/logic";
import { DeviceModelId } from "@ledgerhq/devices";

const currency = getCryptoCurrencyById("polkadot");
const POLKADOT_MIN_SAFE = parseCurrencyUnit(currency.units[0], "0.05");
// FIXME Should be replaced with EXISTENTIAL_DEPOSIT_RECOMMENDED_MARGIN in logic.ts
const POLKADOT_MIN_SAFE = parseCurrencyUnit(currency.units[0], "0.1");
// FIXME Should be replaced with EXISTENTIAL_DEPOSIT in logic.ts
const EXISTENTIAL_DEPOSIT = parseCurrencyUnit(currency.units[0], "1.0");
const MIN_LOCKED_BALANCE_REQ = parseCurrencyUnit(currency.units[0], "1.0");
const polkadot: AppSpec<Transaction> = {
Expand Down Expand Up @@ -49,8 +51,9 @@ const polkadot: AppSpec<Transaction> = {
mutations: [
{
name: "send 50%~",
maxRun: 1,
maxRun: 2,
transaction: ({ account, siblings, bridge }) => {
invariant(account.polkadotResources, "polkadot");
const sibling = pickSiblings(siblings, 2);
let amount = account.spendableBalance
.div(1.9 + 0.2 * Math.random())
Expand Down Expand Up @@ -81,18 +84,11 @@ const polkadot: AppSpec<Transaction> = {
},
{
name: "bond - bondExtra",
maxRun: 2,
maxRun: 1,
transaction: ({ account, bridge }) => {
invariant(account.polkadotResources, "polkadot");
invariant(canBond(account), "can't bond");
const { minimumBondBalance } = getCurrentPolkadotPreloadData();
invariant(
new BigNumber(100000).gt(
getMinimumAmountToBond(account, new BigNumber(minimumBondBalance))
),
"can't bond because too much unbond"
);
const { polkadotResources } = account;
invariant(polkadotResources, "polkadot");
invariant(hasMinimumBondBalance(account), "not enough balance to bond");
const options: {
recipient?: string;
rewardDestination?: string;
Expand Down Expand Up @@ -134,14 +130,14 @@ const polkadot: AppSpec<Transaction> = {
},
{
name: "unbond",
maxRun: 1,
maxRun: 2,
transaction: ({ account, bridge }) => {
invariant(canUnbond(account), "can't unbond");
const { polkadotResources } = account;
invariant(polkadotResources, "polkadot");
invariant(canUnbond(account), "can't unbond");
invariant(
account.spendableBalance.gt(POLKADOT_MIN_SAFE),
"cant cover fee"
"can't cover fee"
);
const amount = (polkadotResources as PolkadotResources).lockedBalance
.minus((polkadotResources as PolkadotResources).unlockingBalance)
Expand All @@ -163,17 +159,15 @@ const polkadot: AppSpec<Transaction> = {
name: "rebond",
maxRun: 1,
transaction: ({ account, bridge }) => {
const { polkadotResources } = account;
invariant(polkadotResources, "polkadot");
invariant(
account.polkadotResources?.unlockingBalance.gt(
MIN_LOCKED_BALANCE_REQ
),
polkadotResources?.unlockingBalance.gt(MIN_LOCKED_BALANCE_REQ),
"can't rebond"
);
const { polkadotResources } = account;
invariant(polkadotResources, "polkadot");
invariant(
account.spendableBalance.gt(POLKADOT_MIN_SAFE),
"cant cover fee"
"can't cover fee"
);
const amount = BigNumber.maximum(
(polkadotResources as PolkadotResources).unlockingBalance.times(0.2),
Expand All @@ -196,9 +190,8 @@ const polkadot: AppSpec<Transaction> = {
name: "nominate",
maxRun: 1,
transaction: ({ account, bridge }) => {
invariant(account.polkadotResources, "polkadot");
invariant(canNominate(account), "can't nominate");
const { polkadotResources } = account;
invariant(polkadotResources, "polkadot");
invariant(
account.spendableBalance.gt(POLKADOT_MIN_SAFE),
"cant cover fee"
Expand All @@ -221,6 +214,30 @@ const polkadot: AppSpec<Transaction> = {
};
},
},
{
name: "withdraw",
maxRun: 2,
transaction: ({ account, bridge }) => {
const { polkadotResources } = account;
invariant(polkadotResources, "polkadot");
invariant(
polkadotResources?.unlockedBalance.gt(0),
"nothing to withdraw"
);
invariant(
account.spendableBalance.gt(POLKADOT_MIN_SAFE),
"can't cover fee"
);
return {
transaction: bridge.createTransaction(account),
updates: [
{
mode: "withdrawUnbonded",
},
],
};
},
},
],
};
export default {
Expand Down