Skip to content

Commit

Permalink
Update balance precheck to handle large values (#329)
Browse files Browse the repository at this point in the history
* Update balance precheck to handle large values

Signed-off-by: Nana-EC <[email protected]>
  • Loading branch information
Nana-EC authored Jul 12, 2022
1 parent 3461308 commit dde5f1c
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 5 deletions.
5 changes: 5 additions & 0 deletions packages/relay/src/lib/clients/sdkClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ export class SDKClient {
.setAccountId(AccountId.fromString(account)), this.clientMain, callerName);
}

async getAccountBalanceInTinyBar(account: string, callerName: string): Promise<BigNumber> {
const balance = await this.getAccountBalance(account, callerName);
return balance.hbars.to(HbarUnit.Tinybar);
}

async getAccountBalanceInWeiBar(account: string, callerName: string): Promise<BigNumber> {
const balance = await this.getAccountBalance(account, callerName);
return SDKClient.HbarToWeiBar(balance);
Expand Down
7 changes: 4 additions & 3 deletions packages/relay/src/lib/precheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { predefined } from './errors';
import { MirrorNodeClient, SDKClient } from './clients';
import {EthImpl} from "./eth";
import {Logger} from "pino";
import constants from './constants';

export class Precheck {
private mirrorNodeClient: MirrorNodeClient;
Expand Down Expand Up @@ -107,12 +108,12 @@ export class Precheck {

try {
const { account }: any = await this.mirrorNodeClient.getAccount(tx.from!);
const accountBalance = await this.sdkClient.getAccountBalanceInWeiBar(account, callerName);
const tinybars = await this.sdkClient.getAccountBalanceInTinyBar(account, callerName);

result.passes = ethers.ethers.BigNumber.from(accountBalance.toString()).gte(txTotalValue);
result.passes = ethers.ethers.BigNumber.from(tinybars.toString()).mul(constants.TINYBAR_TO_WEIBAR_COEF).gte(txTotalValue);

if (!result.passes) {
this.logger.trace('Failed balance precheck for sendRawTransaction(transaction=%s, totalValue=%s, accountBalance=%s)', transaction, txTotalValue, accountBalance);
this.logger.trace('Failed balance precheck for sendRawTransaction(transaction=%s, totalValue=%s, accountTinyBarBalance=%s)', transaction, txTotalValue, tinybars);
}
} catch (error: any) {
this.logger.trace('Error on balance precheck for sendRawTransaction(transaction=%s, totalValue=%s, error=%s)', transaction, txTotalValue, error.message);
Expand Down
87 changes: 85 additions & 2 deletions packages/relay/tests/lib/precheck.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import { expect } from 'chai';
import { Registry } from 'prom-client';
import { BigNumber } from 'ethers';
import { Hbar, HbarUnit } from '@hashgraph/sdk';
const registry = new Registry();

import sinon from 'sinon';
Expand All @@ -29,13 +31,15 @@ import {MirrorNodeClient, SDKClient} from "../../src/lib/clients";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import constants from '../../src/lib/constants';
import { predefined } from './../../src/lib/errors';
const logger = pino();

describe('Precheck', async function() {

const txWithMatchingChainId = '0x02f87482012a0485a7a358200085a7a3582000832dc6c09400000000000000000000000000000000000003f78502540be40080c001a006f4cd8e6f84b76a05a5c1542a08682c928108ef7163d9c1bf1f3b636b1cd1fba032097cbf2dda17a2dcc40f62c97964d9d930cdce2e8a9df9a8ba023cda28e4ad';
const txWithNonMatchingChainId = '0xf86a0385a7a3582000832dc6c09400000000000000000000000000000000000003f78502540be400801ca06750e92db52fa708e27f94f27e0cfb7f5800f9b657180bb2e94c1520cfb1fb6da01bec6045068b6db38b55017bb8b50166699384bc1791fd8331febab0cf629a2a';
const defaultGasPrice = 720_000_000_000;
let sdkInstance;

let precheck: Precheck;
let mock: MockAdapter;
Expand All @@ -56,10 +60,15 @@ describe('Precheck', async function() {

// @ts-ignore
const mirrorNodeInstance = new MirrorNodeClient(process.env.MIRROR_NODE_URL, logger.child({ name: `mirror-node` }), registry, instance);
const sdkInstance = sinon.createStubInstance(SDKClient);
sdkInstance = sinon.createStubInstance(SDKClient);
precheck = new Precheck(mirrorNodeInstance, sdkInstance, logger, '0x12a');
});

this.beforeEach(() => {
// reset mock
mock.reset();
});

describe('chainId', async function() {
it('should return true for matching chainId', async function() {
const result = precheck.chainId(txWithMatchingChainId);
Expand Down Expand Up @@ -96,5 +105,79 @@ describe('Precheck', async function() {
expect(result.error).to.exist;
expect(result.passes).to.eq(false);
});
})
});

describe('balance', async function() {
// sending 2 hbars
const transaction = '0x02f876820128078459682f0086018a4c7747008252089443cb701defe8fc6ed04d7bddf949618e3c575fe1881bc16d674ec8000080c001a0b8c604e08c15a7acc8c898a1bbcc41befcd0d120b64041d1086381c7fc2a5339a062eabec286592a7283c90ce90d97f9f8cf9f6c0cef4998022660e7573c046a46';
const mirrorAccountsPath = 'accounts/0xF8A44f9a4E4c452D25F5aE0F5d7970Ac9522a3C8';
const accountId = '0.1.2';

it('should return false for 1 hbar', async function() {
mock.onGet(mirrorAccountsPath).reply(200, {
account: accountId
});

sdkInstance.getAccountBalanceInTinyBar.returns(Hbar.from(1, HbarUnit.Hbar).to(HbarUnit.Tinybar));
const result = await precheck.balance(transaction, 'sendRawTransaction');
expect(result).to.exist;
expect(result.error.message).to.eq(predefined.INSUFFICIENT_ACCOUNT_BALANCE.message);
expect(result.passes).to.eq(false);
});

it('should return true for 10 hbar', async function() {
mock.onGet(mirrorAccountsPath).reply(200, {
account: accountId
});

sdkInstance.getAccountBalanceInTinyBar.returns(Hbar.from(10, HbarUnit.Hbar).to(HbarUnit.Tinybar));
const result = await precheck.balance(transaction, 'sendRawTransaction');
expect(result).to.exist;
expect(result.passes).to.eq(true);
});

it('should return true for 100 hbar', async function() {
mock.onGet(mirrorAccountsPath).reply(200, {
account: accountId
});

sdkInstance.getAccountBalanceInTinyBar.returns(Hbar.from(100, HbarUnit.Hbar).to(HbarUnit.Tinybar));
const result = await precheck.balance(transaction, 'sendRawTransaction');
expect(result).to.exist;
expect(result.passes).to.eq(true);
});

it('should return true for 10000 hbar', async function() {
mock.onGet(mirrorAccountsPath).reply(200, {
account: accountId
});

sdkInstance.getAccountBalanceInTinyBar.returns(Hbar.from(10_000, HbarUnit.Hbar).to(HbarUnit.Tinybar));
const result = await precheck.balance(transaction, 'sendRawTransaction');
expect(result).to.exist;
expect(result.passes).to.eq(true);
});

it('should return true for 100000 hbar', async function() {
mock.onGet(mirrorAccountsPath).reply(200, {
account: accountId
});

sdkInstance.getAccountBalanceInTinyBar.returns(Hbar.from(100_000, HbarUnit.Hbar).to(HbarUnit.Tinybar));
const result = await precheck.balance(transaction, 'sendRawTransaction');
expect(result).to.exist;
expect(result.passes).to.eq(true);
});

it('should return true for 50_000_000_000 hbar', async function() {
mock.onGet(mirrorAccountsPath).reply(200, {
account: accountId
});

sdkInstance.getAccountBalanceInTinyBar.returns(Hbar.from(50_000_000_000, HbarUnit.Hbar).to(HbarUnit.Tinybar));
const result = await precheck.balance(transaction, 'sendRawTransaction');
expect(result).to.exist;
expect(result.passes).to.eq(true);
});
});
});

0 comments on commit dde5f1c

Please sign in to comment.