Skip to content

Commit

Permalink
add support for random decimals in Amount
Browse files Browse the repository at this point in the history
  • Loading branch information
louzhixian committed Nov 12, 2020
1 parent 4db55dc commit 83fc880
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 56 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lay2/pw-core",
"version": "0.3.20-beta.2",
"version": "0.3.20-beta.3",
"description": "the javascript sdk of pw-sdk",
"main": "build/main/index.js",
"typings": "build/main/index.d.ts",
Expand Down Expand Up @@ -109,4 +109,4 @@
"**/*.spec.js"
]
}
}
}
16 changes: 15 additions & 1 deletion src/models/amount.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PWCore, { ChainID } from '../core';
import { DummyCollector } from '../collectors/dummy-collector';
import { Amount, AmountUnit } from '.';
import { DummyProvider } from '../providers/dummy-provider';
import JSBI from 'jsbi';

test.before(async () => {
await new PWCore('https://aggron.ckb.dev').init(
Expand Down Expand Up @@ -127,4 +128,17 @@ test('to hex string', (t) => {
t.is(shannonFull.toHexString(), '0xe94c0e8734');
});

test.todo('random decimal test');
// tests for random decimals

const d0 = new Amount('10', 0);
const d1 = new Amount('1', 1);
const d2 = new Amount('0.1', 2);
const p = new Amount('0.00361', AmountUnit.ckb);

test.only('to BigInt', (t) => {
t.is(d0.toBigInt().toString(), JSBI.BigInt(10).toString());
t.is(d1.toBigInt().toString(), JSBI.BigInt(10).toString());
t.is(d2.toBigInt().toString(), JSBI.BigInt(10).toString());
t.is(p.toString(), '0.00361');
t.is(p.toString(AmountUnit.shannon), '361000');
});
50 changes: 15 additions & 35 deletions src/models/amount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import JSBI from 'jsbi';
import {
toBigUInt128LE,
readBigUInt128LE,
rationalNumberToBnString,
bnStringToRationalNumber,
rationalNumberToBnString,
} from '../utils';
import { HexStringToBigInt } from 'ckb-js-toolkit';

export enum AmountUnit {
shannon,
Expand Down Expand Up @@ -36,7 +35,7 @@ export class Amount {
mul(val: Amount): Amount {
const res = JSBI.divide(
JSBI.multiply(this.toBigInt(), val.toBigInt()),
JSBI.BigInt(10 ** (val.decimal + this.decimal))
JSBI.BigInt(10 ** (val.decimals + this.decimals))
).toString();
return new Amount(res, AmountUnit.shannon);
}
Expand All @@ -62,52 +61,33 @@ export class Amount {
}

private amount: string;
private decimal: number;

constructor(amount: string, unit?: AmountUnit);
constructor(amount: string, decimal: number = 8) {
if (Number.isNaN(amount)) {
throw new Error(`Amount ${amount} is not a valid number`);
}
amount = `${amount}`;
private decimals: number;

if (!Number.isInteger(decimal) || decimal < 0) {
throw new Error(`Decimal ${decimal} must be a natural number`);
constructor(amount: string, decimals: number | AmountUnit = AmountUnit.ckb) {
if (!Number.isInteger(decimals) || decimals < 0) {
throw new Error(`decimals ${decimals} must be a natural number`);
}
this.decimal = decimal;
this.decimals = decimals;

if (amount.startsWith('0x')) {
amount = HexStringToBigInt(amount).toString();
}

if (decimal === AmountUnit.shannon) {
try {
amount = amount.match(/^0*(\d*)$/)[1];
if (amount === '') {
amount = '0';
}
} catch (e) {
throw new Error(`Amount ${amount} is invalid`);
}
if (Number.isNaN(amount)) {
throw new Error(`amount ${amount} must be a valid number`);
}
this.amount = amount;
this.decimal = decimal;
this.amount = rationalNumberToBnString(amount, decimals);
}

toString(
decimal = AmountUnit.ckb as number,
decimals: number | AmountUnit = AmountUnit.ckb,
options?: FormatOptions
): string {
return bnStringToRationalNumber(
this.toBigInt().toString(),
decimal,
decimals,
options
);
}

toBigInt(decimal?: number) {
return JSBI.BigInt(
rationalNumberToBnString(this.amount, decimal || this.decimal)
);
toBigInt() {
return JSBI.BigInt(this.amount);
}

toHexString() {
Expand Down
2 changes: 1 addition & 1 deletion src/models/sudt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PWCore from '../core';

export interface SudtInfo {
symbol: string;
decimal: number;
decimals: number;
name: string;
}
export class SUDT {
Expand Down
39 changes: 22 additions & 17 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ export const ckbToShannon = (ckbAmount: string): string =>

export const bnStringToRationalNumber = (
bn: string,
decimal: number,
decimals: number,
options: FormatOptions
) => {
if (!Number.isInteger(decimal) || decimal < 0) {
throw new Error("value of 'decimal' must be a positive integer");
if (!Number.isInteger(decimals) || decimals < 0) {
throw new Error("value of 'decimals' must be a natural integer");
}

const n = new Decimal(bn);
Expand All @@ -30,8 +30,8 @@ export const bnStringToRationalNumber = (

let int = bn;
let dec = '';
if (decimal > 0) {
const intLen = bn.length - decimal;
if (decimals > 0) {
const intLen = bn.length - decimals;
int = intLen > 0 ? bn.substr(0, intLen) : '0';
dec = intLen > 0 ? bn.slice(intLen) : `${'0'.repeat(-intLen)}${bn}`;
dec = new Decimal(`0.${dec}`).toFixed().slice(2);
Expand All @@ -41,20 +41,21 @@ export const bnStringToRationalNumber = (
if (options.fixed) {
if (
!Number.isInteger(options.fixed) ||
options.fixed < 1 ||
options.fixed > decimal
options.fixed < 1
// || options.fixed > decimals
) {
throw new Error(
`value of \'fixed\' must be a positive integer and not bigger than decimal value ${decimal}`
// `value of \'fixed\' must be a positive integer and not bigger than decimals value ${decimals}`
`value of \'fixed\' must be a positive integer`
);
}
const res = new Decimal(`0.${dec}`).toFixed(options.fixed).split('.');
dec = res[1];
if (res[0] === '1') {
int = JSBI.add(JSBI.BigInt(int), JSBI.BigInt(1)).toString();
}
} else if (options.pad && dec.length < decimal) {
dec = `${dec}${'0'.repeat(decimal - dec.length)}`;
} else if (options.pad && dec.length < decimals) {
dec = `${dec}${'0'.repeat(decimals - dec.length)}`;
}
if (options.commify) {
int = int.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
Expand All @@ -75,20 +76,24 @@ export const bnStringToRationalNumber = (
return int;
};

export const rationalNumberToBnString = (rational: string, decimal: number) => {
if (!Number.isInteger(decimal) || decimal < 0) {
throw new Error("value of 'decimal' must be a positive integer");
export const rationalNumberToBnString = (
rational: string,
decimals: number
) => {
if (!Number.isInteger(decimals) || decimals < 0) {
throw new Error("value of 'decimals' must be a natural integer");
}
if (decimal === 0) return rational;
if (decimals === 0) return rational;

if (rational === '0x') rational = '0';
const r = new Decimal(rational);
if (r.dp() > decimal) {
if (r.dp() > decimals) {
throw new Error(
`Decimal ${decimal} is smaller than the digits number of ${rational}`
`decimals ${decimals} is smaller than the digits number of ${rational}`
);
}

return `${rational.split('.').join('')}${'0'.repeat(decimal - r.dp())}`;
return `${rational.split('.').join('')}${'0'.repeat(decimals - r.dp())}`;
};

// from @lumos/helper
Expand Down

0 comments on commit 83fc880

Please sign in to comment.