From bb184cafb1a5892b426a2821c34979a270f16093 Mon Sep 17 00:00:00 2001 From: Troy Kessler <43882936+troykessler@users.noreply.github.com> Date: Wed, 3 Jul 2024 14:52:31 +0200 Subject: [PATCH] fix: support floating values (#141) * fix: support floating values --- common/coins/package.json | 8 ++-- common/coins/src/index.ts | 68 ++++++++++++++++++--------------- common/coins/test/coins.spec.ts | 16 +++++++- yarn.lock | 12 +++--- 4 files changed, 61 insertions(+), 43 deletions(-) diff --git a/common/coins/package.json b/common/coins/package.json index 893dbdf5..b397986f 100644 --- a/common/coins/package.json +++ b/common/coins/package.json @@ -1,6 +1,6 @@ { "name": "@kyvejs/coins", - "version": "1.0.1", + "version": "1.0.2", "main": "./dist/index.js", "types": "./dist/index.d.ts", "files": [ @@ -23,13 +23,13 @@ }, "dependencies": { "@cosmjs/amino": "^0.32.3", - "bn.js": "^5.2.1" + "bignumber.js": "^9.1.2" }, "devDependencies": { - "jest": "^29.7.0", "@types/jest": "^29.5.12", + "jest": "^29.7.0", "rimraf": "^3.0.2", "typescript": "^4.5.5", - "@types/bn.js": "^5.1.5" + "@types/bignumber.js": "^5.0.0" } } diff --git a/common/coins/src/index.ts b/common/coins/src/index.ts index 32afa28a..672db94e 100644 --- a/common/coins/src/index.ts +++ b/common/coins/src/index.ts @@ -1,18 +1,22 @@ import { parseCoins, Coin } from "@cosmjs/amino"; -import BN from "bn.js"; +import BigNumber from "bignumber.js"; + +BigNumber.set({ + ROUNDING_MODE: 3, +}); type CoinArgs = String[] | Coin[] | Coins[]; export class Coins { - private coinMap: Map = new Map(); + private coinMap: Map = new Map(); private get coins(): Coin[] { return this.sortCoins( Array.from(this.coinMap.entries()).map(([denom, amount]) => ({ denom, - amount: amount.toString(), + amount: amount.toFixed(0), })) - ).filter((coin) => !new BN(coin.amount).isZero()); + ).filter((coin) => !new BigNumber(coin.amount).isZero()); } /** @@ -179,7 +183,9 @@ export class Coins { * @return {boolean} */ public isAnyNegative(): boolean { - return Array.from(this.coinMap.values()).some((amount) => amount.isNeg()); + return Array.from(this.coinMap.values()).some((amount) => + amount.isNegative() + ); } /** @@ -192,7 +198,7 @@ export class Coins { public isAllPositive(): boolean { return ( !this.empty() && - Array.from(this.coinMap.values()).every((amount) => amount.gtn(0)) + Array.from(this.coinMap.values()).every((amount) => amount.gt(0)) ); } @@ -211,7 +217,7 @@ export class Coins { this.coinArgsToCoins(...coinsB).forEach((coin) => { this.coinMap.set( coin.denom, - (this.coinMap.get(coin.denom) || new BN(0)).add(new BN(coin.amount)) + (this.coinMap.get(coin.denom) || new BigNumber(0)).plus(coin.amount) ); }); @@ -235,7 +241,7 @@ export class Coins { this.coinArgsToCoins(...coinsB).forEach((coin) => { this.coinMap.set( coin.denom, - (this.coinMap.get(coin.denom) || new BN(0)).sub(new BN(coin.amount)) + (this.coinMap.get(coin.denom) || new BigNumber(0)).minus(coin.amount) ); }); @@ -257,7 +263,10 @@ export class Coins { */ public mul(value: number | string): Coins { this.coinMap.forEach((amount, denom) => { - this.coinMap.set(denom, amount.mul(new BN(value))); + this.coinMap.set( + denom, + new BigNumber(amount.multipliedBy(value).toFixed(0)) + ); }); return new Coins(this); @@ -280,7 +289,7 @@ export class Coins { */ public quo(value: number | string): Coins { this.coinMap.forEach((amount, denom) => { - this.coinMap.set(denom, new BN(amount.div(new BN(value)).toString())); + this.coinMap.set(denom, amount.idiv(value)); }); return new Coins(this); @@ -304,9 +313,9 @@ export class Coins { return new Coins( ...this.coinArgsToCoins(...coinsB).map((coin) => ({ denom: coin.denom, - amount: BN.min( - this.coinMap.get(coin.denom) || new BN(0), - new BN(coin.amount) + amount: BigNumber.min( + this.coinMap.get(coin.denom) || new BigNumber(0), + coin.amount ).toString(), })) ); @@ -330,7 +339,10 @@ export class Coins { this.coinArgsToCoins(...coinsB).forEach((coin) => { this.coinMap.set( coin.denom, - BN.max(this.coinMap.get(coin.denom) || new BN(0), new BN(coin.amount)) + BigNumber.max( + this.coinMap.get(coin.denom) || new BigNumber(0), + coin.amount + ) ); }); @@ -357,7 +369,7 @@ export class Coins { return this.coinArgsToCoins(...coinsB).every( (coin) => this.coinMap.has(coin.denom) && - this.coinMap.get(coin.denom)!.gte(new BN(coin.amount)) + this.coinMap.get(coin.denom)!.gte(coin.amount) ); } @@ -381,7 +393,7 @@ export class Coins { return this.coinArgsToCoins(...coinsB).every( (coin) => this.coinMap.has(coin.denom) && - this.coinMap.get(coin.denom)!.gt(new BN(coin.amount)) + this.coinMap.get(coin.denom)!.gt(coin.amount) ); } @@ -406,8 +418,7 @@ export class Coins { return Array.from(this.coinMap.keys()).every( (denom) => - coins.has(denom) && - this.coinMap.get(denom)!.lte(new BN(coins.get(denom)!)) + coins.has(denom) && this.coinMap.get(denom)!.lte(coins.get(denom)!) ); } @@ -432,8 +443,7 @@ export class Coins { return Array.from(this.coinMap.keys()).every( (denom) => - coins.has(denom) && - this.coinMap.get(denom)!.lt(new BN(coins.get(denom)!)) + coins.has(denom) && this.coinMap.get(denom)!.lt(coins.get(denom)!) ); } @@ -458,8 +468,7 @@ export class Coins { return Array.from(this.coinMap.keys()).some( (denom) => - coins.has(denom) && - this.coinMap.get(denom)!.gte(new BN(coins.get(denom)!)) + coins.has(denom) && this.coinMap.get(denom)!.gte(coins.get(denom)!) ); } @@ -484,8 +493,7 @@ export class Coins { return Array.from(this.coinMap.keys()).some( (denom) => - coins.has(denom) && - this.coinMap.get(denom)!.gt(new BN(coins.get(denom)!)) + coins.has(denom) && this.coinMap.get(denom)!.gt(coins.get(denom)!) ); } @@ -510,8 +518,7 @@ export class Coins { return Array.from(this.coinMap.keys()).some( (denom) => - coins.has(denom) && - this.coinMap.get(denom)!.lte(new BN(coins.get(denom)!)) + coins.has(denom) && this.coinMap.get(denom)!.lte(coins.get(denom)!) ); } @@ -536,8 +543,7 @@ export class Coins { return Array.from(this.coinMap.keys()).some( (denom) => - coins.has(denom) && - this.coinMap.get(denom)!.lt(new BN(coins.get(denom)!)) + coins.has(denom) && this.coinMap.get(denom)!.lt(coins.get(denom)!) ); } @@ -565,11 +571,11 @@ export class Coins { return coins; } - private coinArgsToMap(...coinArgs: CoinArgs): Map { - const map: Map = new Map(); + private coinArgsToMap(...coinArgs: CoinArgs): Map { + const map: Map = new Map(); this.coinArgsToCoins(...coinArgs).forEach((coin) => { - map.set(coin.denom, new BN(coin.amount)); + map.set(coin.denom, new BigNumber(coin.amount)); }); return map; diff --git a/common/coins/test/coins.spec.ts b/common/coins/test/coins.spec.ts index cd91c2ac..ca5d67e2 100644 --- a/common/coins/test/coins.spec.ts +++ b/common/coins/test/coins.spec.ts @@ -34,6 +34,10 @@ describe("coins.ts", () => { expect(() => new Coins("10acoin,30B")).toThrow( new Error("Got an invalid coin string") ); + // float values + expect(() => new Coins("10acoin,0.2bcoin")).toThrow( + new Error("Got an invalid coin string") + ); // --- Coin --- @@ -319,9 +323,13 @@ describe("coins.ts", () => { "" ); - expect(new Coins("10acoin,20bcoin,30ccoin").mul("3").toString()).toEqual( + expect(new Coins("10acoin,20bcoin,30ccoin").mul(3).toString()).toEqual( "30acoin,60bcoin,90ccoin" ); + + expect(new Coins("10acoin,20bcoin,17ccoin").mul("0.1").toString()).toEqual( + "1acoin,2bcoin,1ccoin" + ); }); test("quo", () => { @@ -337,8 +345,12 @@ describe("coins.ts", () => { expect(new Coins("4acoin").quo(8).toString()).toEqual(""); + expect(new Coins("10acoin,20bcoin,30ccoin").quo(0.2).toString()).toEqual( + "50acoin,100bcoin,150ccoin" + ); + expect(() => new Coins("10acoin,20bcoin,30ccoin").quo(0)).toThrow( - new Error("Assertion failed") + new Error("Got an invalid coin string") ); }); diff --git a/yarn.lock b/yarn.lock index 5541e62f..ab96f44e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2093,12 +2093,12 @@ dependencies: "@babel/types" "^7.20.7" -"@types/bn.js@^5.1.5": - version "5.1.5" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.5.tgz#2e0dacdcce2c0f16b905d20ff87aedbc6f7b4bf0" - integrity sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A== +"@types/bignumber.js@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/bignumber.js/-/bignumber.js-5.0.0.tgz#d9f1a378509f3010a3255e9cc822ad0eeb4ab969" + integrity sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA== dependencies: - "@types/node" "*" + bignumber.js "*" "@types/clone@^2.1.1": version "2.1.4" @@ -2934,7 +2934,7 @@ bigint-buffer@^1.1.5: dependencies: bindings "^1.3.0" -bignumber.js@9.1.2, bignumber.js@^9.0.0, bignumber.js@^9.0.1, bignumber.js@^9.0.2, bignumber.js@^9.1.0, bignumber.js@^9.1.2: +bignumber.js@*, bignumber.js@9.1.2, bignumber.js@^9.0.0, bignumber.js@^9.0.1, bignumber.js@^9.0.2, bignumber.js@^9.1.0, bignumber.js@^9.1.2: version "9.1.2" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==