From d482d3942e258e26c9cc4670ad46231050c1f18a Mon Sep 17 00:00:00 2001 From: b4rtaz Date: Mon, 25 Jul 2022 15:54:00 +0200 Subject: [PATCH 1/7] own implementation of BigNumber. --- .vscode/settings.json | 9 + packages/core/package.json | 6 +- .../src/dataTypes/BigNumber/BigNumber.test.ts | 206 +++++++++++ .../core/src/dataTypes/BigNumber/BigNumber.ts | 140 ++++++++ .../core/src/dataTypes/BigNumber/index.ts | 1 + packages/core/src/dataTypes/index.ts | 1 + packages/evmApi/package.json | 3 +- .../resolvers/account/getTokenTransfers.ts | 3 +- .../src/resolvers/account/getTransactions.ts | 3 +- .../src/resolvers/token/getTokenAllowance.ts | 3 +- packages/evmUtils/package.json | 2 - .../src/dataTypes/EvmNative/EvmNative.ts | 11 +- .../EvmTransaction/EvmTransaction.ts | 3 +- .../EvmTransaction/EvmTransactionTypes.ts | 2 +- .../EvmTransactionReceipt.test.ts | 2 +- .../EvmTransactionReceipt.ts | 3 +- .../EvmTransactionReceiptTypes.ts | 2 +- .../EvmTransactionResponse.ts | 5 +- .../EvmTransactionResponseTypes.ts | 2 +- packages/solApi/package.json | 3 +- packages/solUtils/package.json | 2 - .../src/dataTypes/SolNative/SolNative.ts | 26 +- yarn.lock | 328 +----------------- 23 files changed, 406 insertions(+), 360 deletions(-) create mode 100644 packages/core/src/dataTypes/BigNumber/BigNumber.test.ts create mode 100644 packages/core/src/dataTypes/BigNumber/BigNumber.ts create mode 100644 packages/core/src/dataTypes/BigNumber/index.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index a03b4b5496..8f16b818b5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,14 @@ "search.exclude": { "**/.git": true, "**/node_modules": true + }, + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true, + "**/Thumbs.db": true, + "**/node_modules": true } } diff --git a/packages/core/package.json b/packages/core/package.json index 9513598355..5c10b62a12 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -26,11 +26,11 @@ "devDependencies": { "prettier": "^2.5.1", "typed-emitter": "^2.1.0", - "typescript": "^4.5.5" + "typescript": "^4.5.5", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/units": "^5.6.0" }, "dependencies": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/units": "^5.6.0", "@xstate/fsm": "^2.0.0", "eventemitter3": "^4.0.7", "axios": "^0.27.2" diff --git a/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts b/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts new file mode 100644 index 0000000000..4355d0d1b6 --- /dev/null +++ b/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts @@ -0,0 +1,206 @@ +import { BigNumber as MoralisBigNumber } from './BigNumber'; +import { parseFixed, BigNumber as EthersBigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +describe('BigNumber', () => { + describe('from()', () => { + it('parses string', () => { + const parseMoralis = (value: string) => { + const v = MoralisBigNumber.from(value, 0); + return { + string: v.toString(), + json: v.toJSON(), + dec0: v.toDecimal(0), + dec18: v.toDecimal(18), + dec5: v.toDecimal(5), + }; + }; + const parseEthers = (value: string) => { + const v = parseFixed(value, 0); + return { + string: v.toString(), + json: v.toJSON().hex, + dec0: formatUnits(v, 0), + dec18: formatUnits(v, 18), + dec5: formatUnits(v, 5), + }; + }; + + function test( + parse: (value: string) => { string: string; json: string; dec18: string; dec5: string; dec0: string }, + ) { + const v = parse('1000000000000000000'); + expect(v.string).toEqual('1000000000000000000'); + expect(v.json).toEqual('0x0de0b6b3a7640000'); + expect(v.dec0).toEqual('1000000000000000000'); + expect(v.dec18).toEqual('1.0'); + expect(v.dec5).toEqual('10000000000000.0'); + } + + test(parseMoralis); + test(parseEthers); + }); + + it('parses hex', () => { + const parseHexMoralis = (value: string) => MoralisBigNumber.from(value).toString(); + const parseHexEthers = (value: string) => EthersBigNumber.from(value).toString(); + + function test(parseHex: (value: string) => string) { + expect(parseHex('0x1')).toEqual('1'); + expect(parseHex('0x100')).toEqual('256'); + expect(parseHex('0x0')).toEqual('0'); + expect(parseHex('-0x0')).toEqual('0'); + expect(parseHex('-0x100')).toEqual('-256'); + } + + test(parseHexMoralis); + test(parseHexEthers); + }); + + it('parses decimal', () => { + const parseMoralis = (value: string, decimals: number) => MoralisBigNumber.from(value, decimals).toString(); + const parseEthers = (value: string, decimals: number) => parseFixed(value, decimals).toString(); + + function test(parse: (value: string, decimal: number) => string) { + expect(parse('0', 0)).toEqual('0'); + expect(parse('0.0', 1)).toEqual('0'); + expect(parse('0.0', 6)).toEqual('0'); + expect(parse('0.1', 1)).toEqual('1'); + expect(parse('-0.1', 1)).toEqual('-1'); + expect(parse('-0.01', 2)).toEqual('-1'); + expect(parse('0.1', 2)).toEqual('10'); + expect(parse('0.1', 4)).toEqual('1000'); + expect(parse('1', 2)).toEqual('100'); + expect(parse('-1', 2)).toEqual('-100'); + expect(parse('-25', 2)).toEqual('-2500'); + expect(parse('999', 0)).toEqual('999'); + expect(parse('999', 2)).toEqual('99900'); + expect(parse('1.1', 18)).toEqual('1100000000000000000'); + expect(parse('25.12345', 18)).toEqual('25123450000000000000'); + expect(parse('-25.12345', 18)).toEqual('-25123450000000000000'); + expect(parse('0.128', 18)).toEqual('128000000000000000'); + } + + test(parseMoralis); + test(parseEthers); + }); + + it('throws an error when fractional part is wrong', () => { + const expectedError = 'value has too long fractional part'; + expect(() => MoralisBigNumber.from('0.0', 0)).toThrowError(expectedError); + expect(() => MoralisBigNumber.from('0.0001', 1)).toThrowError(expectedError); + expect(() => MoralisBigNumber.from('0.0000001', 4)).toThrowError(expectedError); + expect(() => MoralisBigNumber.from('0.1', 0)).toThrowError(expectedError); + expect(() => MoralisBigNumber.from('-0.1', 0)).toThrowError(expectedError); + }); + + it('throws an error when decimals is negative', () => { + expect(() => MoralisBigNumber.from('1', -1)).toThrowError('invalid decimal'); + }); + + it('does not create a new instance if BigNumber instance passed', () => { + const value = MoralisBigNumber.from(0x1); + + expect(MoralisBigNumber.from(value) === value).toBe(true); + }); + }); + + describe('toDecimal()', () => { + it('returns correct decimals', () => { + const toDecimalMoralis = (value: string, decimals: number) => MoralisBigNumber.from(value).toDecimal(decimals); + const toDecimalEthers = (value: string, decimals: number) => formatUnits(value, decimals); + + function test(toDecimal: (value: string, decimals: number) => string) { + expect(toDecimal('0', 0)).toEqual('0'); + expect(toDecimal('-0', 0)).toEqual('0'); + expect(toDecimal('0', 2)).toEqual('0.0'); + expect(toDecimal('-0', 2)).toEqual('0.0'); + expect(toDecimal('0', 10)).toEqual('0.0'); + expect(toDecimal('-256', 0)).toEqual('-256'); + expect(toDecimal('256', 0)).toEqual('256'); + expect(toDecimal('256', 1)).toEqual('25.6'); + expect(toDecimal('-256', 1)).toEqual('-25.6'); + expect(toDecimal('256', 2)).toEqual('2.56'); + expect(toDecimal('256', 5)).toEqual('0.00256'); + expect(toDecimal('256', 10)).toEqual('0.0000000256'); + expect(toDecimal('-256', 10)).toEqual('-0.0000000256'); + expect(toDecimal('256', 18)).toEqual('0.000000000000000256'); + expect(toDecimal('-256', 18)).toEqual('-0.000000000000000256'); + } + + test(toDecimalMoralis); + test(toDecimalEthers); + }); + + it('throws an error if decimals is negative', () => { + expect(() => MoralisBigNumber.from(0).toDecimal(-1)).toThrowError('invalid decimals'); + }); + }); + + it('parses integers', () => { + const parseMoralis = (value: number, decimals: number) => MoralisBigNumber.from(value, decimals).toString(); + const parseEthers = (value: number, decimals: number) => parseFixed(value.toString(), decimals).toString(); + + function test(parse: (value: number, decimals: number) => string) { + expect(parse(0, 0)).toEqual('0'); + expect(parse(10, 0)).toEqual('10'); + expect(parse(-10, 0)).toEqual('-10'); + expect(parse(128, 0)).toEqual('128'); + expect(parse(128, 5)).toEqual('12800000'); + expect(parse(128, 0)).toEqual('128'); + expect(parse(128, 1)).toEqual('1280'); + expect(parse(-128, 1)).toEqual('-1280'); + expect(parse(-128, 10)).toEqual('-1280000000000'); + } + + test(parseMoralis); + test(parseEthers); + }); + + it('eq() returns correct value', () => { + expect(MoralisBigNumber.from(1).eq(MoralisBigNumber.from(1))).toBe(true); + expect(MoralisBigNumber.from(1).eq(MoralisBigNumber.from(-1))).toBe(false); + }); + + it('throws an error when NaN passed', () => { + expect(() => MoralisBigNumber.from(NaN)).toThrowError('The number NaN cannot be converted to a BigInt'); + }); + + it('throws an error when invalid string passed', () => { + function test(input: string, expectedError: string = 'Cannot convert') { + expect(() => MoralisBigNumber.from(input)).toThrowError(expectedError); + } + + test('lorem ipsum'); + test('-x'); + test('x'); + test('##'); + test('$$'); + test('!'); + test('..', 'value has more than one dot'); + test('.', 'value has empty fragments'); + test('', 'value has empty fragments'); + test('-', 'value has empty fragments'); + }); + + it('toHex() returns correct values', () => { + const toHexMoralis = (value: string) => MoralisBigNumber.from(value).toHex(); + const toHexEthers = (value: string) => parseFixed(value).toHexString(); + + function test(toHex: (value: string) => string) { + expect(toHex('10')).toEqual('0x0a'); + expect(toHex('200')).toEqual('0xc8'); + expect(toHex('0')).toEqual('0x00'); + expect(toHex('351')).toEqual('0x015f'); + expect(toHex('123456789')).toEqual('0x075bcd15'); + expect(toHex('-0')).toEqual('0x00'); + expect(toHex('0')).toEqual('0x00'); + expect(toHex('-100')).toEqual('-0x64'); + expect(toHex('-1')).toEqual('-0x01'); + expect(toHex('-123456789')).toEqual('-0x075bcd15'); + } + + test(toHexMoralis); + test(toHexEthers); + }); +}); diff --git a/packages/core/src/dataTypes/BigNumber/BigNumber.ts b/packages/core/src/dataTypes/BigNumber/BigNumber.ts new file mode 100644 index 0000000000..24cc608d1c --- /dev/null +++ b/packages/core/src/dataTypes/BigNumber/BigNumber.ts @@ -0,0 +1,140 @@ +function getMultiplier(decimals: number): bigint { + if (decimals < 0) { + throw new Error('BigNumber: invalid decimals'); + } + // decimals = 0, multiplier = 1 + // decimals = 1, multiplier = 10 + // decimals = 2, multiplier = 100 + // ... + const ten = BigInt(10); + let multiplier = BigInt(1); + while (decimals-- > 0) { + multiplier *= ten; + } + return multiplier; +} + +export type BigNumberPrimitive = number | string | bigint; +export type BigNumberish = BigNumber | BigNumberPrimitive; + +export class BigNumber { + public static from(value: BigNumberish, decimals = 0): BigNumber { + if (value instanceof BigNumber) { + return value; + } + return new BigNumber(BigNumber.parse(value, decimals)); + } + + private static parse(value: BigNumberPrimitive, decimals: number): bigint { + if (typeof value !== 'string') { + return BigInt(value) * getMultiplier(decimals); + } + return BigNumber.parseString(value, decimals); + } + + private static parseString(value: string, decimals: number): bigint { + const isNegative = value.startsWith('-'); + if (isNegative) { + value = value.substring(1); + } + + const fragments = value.startsWith('0x') ? [value] : value.split('.'); + if (fragments.length > 2) { + throw new Error('BigNumber: value has more than one dot'); + } + if (fragments.some((fragment) => !fragment)) { + throw new Error('BigNumber: value has empty fragments'); + } + + const multiplier = getMultiplier(decimals); + let result: bigint; + + if (fragments.length === 1) { + result = BigInt(fragments[0]) * multiplier; + } else { + const whole = fragments[0]; + let fraction = fragments[1]; + if (fraction.length > decimals) { + throw new Error(`BigNumber: value has too long fractional part: ${fraction.length}, max: ${decimals}`); + } + if (fraction.length < decimals) { + fraction = fraction.padEnd(decimals, '0'); + } + + result = BigInt(whole) * multiplier + BigInt(fraction); + } + + if (isNegative) { + result *= BigInt(-1); + } + return result; + } + + public constructor(private readonly value: bigint) {} + + public toBigInt(): bigint { + return this.value; + } + + public mul(value: BigNumberish): BigNumber { + return new BigNumber(this.value * BigNumber.from(value).toBigInt()); + } + + public eq(value: BigNumber): boolean { + return this.value === value.toBigInt(); + } + + public toDecimal(decimals: number): string { + if (decimals < 0) { + throw new Error('BigNumber: invalid decimals'); + } + let result = this.value.toString(); + if (decimals === 0) { + return result; + } + + const isNegative = result.startsWith('-'); + if (isNegative) { + result = result.substring(1); + } + result = result.padStart(decimals, '0'); + + const dot = result.length - decimals; + const whole = dot === 0 ? '0' : result.substring(0, dot); + const fraction = result.substring(dot); + + result = whole + '.' + fraction; + + while (result[result.length - 1] === '0' && result[result.length - 2] !== '.') { + result = result.substring(0, result.length - 1); + } + if (isNegative) { + result = '-' + result; + } + return result; + } + + public toString(): string { + return this.value.toString(); + } + + public toHex(): string { + let result = this.value.toString(16); + const isNegative = result.startsWith('-'); + if (isNegative) { + result = result.substring(1); + } + if (result.length % 2 !== 0) { + result = '0' + result; + } + result = '0x' + result; + if (isNegative) { + result = '-' + result; + } + return result; + } + + public toJSON(): string { + return this.toHex(); + } +} diff --git a/packages/core/src/dataTypes/BigNumber/index.ts b/packages/core/src/dataTypes/BigNumber/index.ts new file mode 100644 index 0000000000..f2773ccedc --- /dev/null +++ b/packages/core/src/dataTypes/BigNumber/index.ts @@ -0,0 +1 @@ +export * from './BigNumber'; diff --git a/packages/core/src/dataTypes/index.ts b/packages/core/src/dataTypes/index.ts index abbe5957ff..2f2974093d 100644 --- a/packages/core/src/dataTypes/index.ts +++ b/packages/core/src/dataTypes/index.ts @@ -1 +1,2 @@ export * from './abstract'; +export * from './BigNumber'; diff --git a/packages/evmApi/package.json b/packages/evmApi/package.json index 22c7859303..7a576c5af6 100644 --- a/packages/evmApi/package.json +++ b/packages/evmApi/package.json @@ -29,7 +29,6 @@ "dependencies": { "@moralisweb3/api-utils": "^2.0.0-alpha.2", "@moralisweb3/core": "^2.0.0-alpha.2", - "@moralisweb3/evm-utils": "^2.0.0-alpha.2", - "ethers": "^5.6.2" + "@moralisweb3/evm-utils": "^2.0.0-alpha.2" } } diff --git a/packages/evmApi/src/resolvers/account/getTokenTransfers.ts b/packages/evmApi/src/resolvers/account/getTokenTransfers.ts index 64dfea4af4..e4c961fd13 100644 --- a/packages/evmApi/src/resolvers/account/getTokenTransfers.ts +++ b/packages/evmApi/src/resolvers/account/getTokenTransfers.ts @@ -1,7 +1,6 @@ -import { Camelize, toCamelCase } from '@moralisweb3/core'; +import { BigNumber, Camelize, toCamelCase } from '@moralisweb3/core'; import { EvmChainish, EvmAddressish, EvmAddress } from '@moralisweb3/evm-utils'; import { operations } from '../../generated/types'; -import { BigNumber } from 'ethers'; import { ApiPaginatedOptions, ApiPaginatedResolver } from '@moralisweb3/api-utils'; import { BASE_URL } from '../../EvmApi'; import { EvmChainResolver } from '../EvmChainResolver'; diff --git a/packages/evmApi/src/resolvers/account/getTransactions.ts b/packages/evmApi/src/resolvers/account/getTransactions.ts index 554abccd75..f83ab350ec 100644 --- a/packages/evmApi/src/resolvers/account/getTransactions.ts +++ b/packages/evmApi/src/resolvers/account/getTransactions.ts @@ -1,5 +1,4 @@ -import { BigNumber } from 'ethers'; -import { Camelize } from '@moralisweb3/core'; +import { BigNumber, Camelize } from '@moralisweb3/core'; import { EvmChainish, EvmAddressish, EvmTransactionReceipt, EvmAddress } from '@moralisweb3/evm-utils'; import { operations } from '../../generated/types'; import { ApiPaginatedOptions, ApiPaginatedResolver } from '@moralisweb3/api-utils'; diff --git a/packages/evmApi/src/resolvers/token/getTokenAllowance.ts b/packages/evmApi/src/resolvers/token/getTokenAllowance.ts index 565dcb5797..ba02736630 100644 --- a/packages/evmApi/src/resolvers/token/getTokenAllowance.ts +++ b/packages/evmApi/src/resolvers/token/getTokenAllowance.ts @@ -1,5 +1,4 @@ -import { BigNumber } from 'ethers'; -import { Camelize } from '@moralisweb3/core'; +import { BigNumber, Camelize } from '@moralisweb3/core'; import { EvmAddress, EvmAddressish, EvmChainish } from '@moralisweb3/evm-utils'; import { ApiResolver } from '@moralisweb3/api-utils'; import { operations } from '../../generated/types'; diff --git a/packages/evmUtils/package.json b/packages/evmUtils/package.json index 93b07469bd..df409ffb0b 100644 --- a/packages/evmUtils/package.json +++ b/packages/evmUtils/package.json @@ -31,9 +31,7 @@ }, "dependencies": { "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", "@ethersproject/transactions": "^5.6.0", - "@ethersproject/units": "^5.6.0", "@moralisweb3/core": "^2.0.0-alpha.2" } } diff --git a/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts b/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts index 8d8e551bca..a8f1404e63 100644 --- a/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts +++ b/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts @@ -1,6 +1,4 @@ -import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits, parseUnits } from '@ethersproject/units'; -import { CoreErrorCode, MoralisCoreError, MoralisData } from '@moralisweb3/core'; +import { BigNumber, BigNumberish, CoreErrorCode, MoralisCoreError, MoralisData } from '@moralisweb3/core'; export type EvmNativeUnit = 'ether' | 'finney' | 'szabo' | 'gwei' | 'mwei' | 'kwei' | 'wei'; @@ -50,8 +48,7 @@ export class EvmNative implements MoralisData { decimals = unitToDecimals[unit]; } - const value = parseUnits(native.toString(), decimals); - + const value = BigNumber.from(native, decimals); return value; } @@ -75,11 +72,11 @@ export class EvmNative implements MoralisData { } public get gwei(): string { - return formatUnits(this.rawValue, 'gwei'); + return this.rawValue.toDecimal(unitToDecimals['gwei']); } public get ether(): string { - return formatUnits(this.rawValue, 'ether'); + return this.rawValue.toDecimal(unitToDecimals['ether']); } public toString(): string { diff --git a/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransaction.ts b/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransaction.ts index a7244b8669..b42140a5d7 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransaction.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransaction.ts @@ -1,6 +1,5 @@ -import { BigNumber } from '@ethersproject/bignumber'; import { accessListify } from '@ethersproject/transactions'; -import { MoralisDataObject, maybe, MoralisCoreError, CoreErrorCode } from '@moralisweb3/core'; +import { MoralisDataObject, maybe, MoralisCoreError, CoreErrorCode, BigNumber } from '@moralisweb3/core'; import { EvmAddress } from '../EvmAddress'; import { EvmChain } from '../EvmChain'; import { EvmTransactionResponse } from '../EvmTransactionResponse/EvmTransactionResponse'; diff --git a/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransactionTypes.ts b/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransactionTypes.ts index e15bb4a8fc..23db13ff4e 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransactionTypes.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransactionTypes.ts @@ -1,4 +1,4 @@ -import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; +import { BigNumber, BigNumberish } from '@moralisweb3/core'; import { EvmAddressish, EvmAddress } from '../EvmAddress'; import { EvmChain } from '../EvmChain'; import { EvmChainish } from '../EvmChain'; diff --git a/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.test.ts b/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.test.ts index 4fe6771bf1..0f81041a1e 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.test.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.test.ts @@ -1,4 +1,4 @@ -import { BigNumber } from '@ethersproject/bignumber'; +import { BigNumber } from '@moralisweb3/core'; import { setupEvmUtils } from '../../test/setup'; import { EvmTransactionLogInput } from '../EvmTransactionLog'; import { EvmTransactionResponse, EvmTransactionResponseInput } from '../EvmTransactionResponse'; diff --git a/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.ts b/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.ts index 44b5e42cfc..591109b9f5 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.ts @@ -1,5 +1,4 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { MoralisDataObject, maybe } from '@moralisweb3/core'; +import { MoralisDataObject, maybe, BigNumber } from '@moralisweb3/core'; import { EvmAddress } from '../EvmAddress'; import { EvmNative } from '../EvmNative'; import { EvmTransactionLog } from '../EvmTransactionLog'; diff --git a/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceiptTypes.ts b/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceiptTypes.ts index ba5f07ef7c..69b5f77b76 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceiptTypes.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceiptTypes.ts @@ -1,4 +1,4 @@ -import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { BigNumber, BigNumberish } from '@moralisweb3/core'; import { EvmAddress, EvmAddressish } from '../EvmAddress'; import { EvmTransactionLog, EvmTransactionLogInput } from '../EvmTransactionLog'; import { EvmTransactionResponse } from '../EvmTransactionResponse/EvmTransactionResponse'; diff --git a/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponse.ts b/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponse.ts index 53510adc35..73fc711e52 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponse.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponse.ts @@ -1,5 +1,4 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { CoreErrorCode, MoralisCoreError, MoralisDataObject, maybe } from '@moralisweb3/core'; +import { CoreErrorCode, MoralisCoreError, MoralisDataObject, maybe, BigNumber } from '@moralisweb3/core'; import { EvmAddress } from '../EvmAddress'; import { EvmChain } from '../EvmChain'; import { EvmNative } from '../EvmNative'; @@ -43,7 +42,7 @@ export class EvmTransactionResponse implements MoralisDataObject { static parse(value: EvmTransactionResponseInput): EvmTransactionResponseData { return { hash: value.hash, - nonce: BigNumber.from(value.nonce), + nonce: BigNumber.from(value.nonce || 0), // TODO: what if nonce is empty? should be zero? chain: EvmChain.create(value.chain), from: EvmAddress.create(value.from), diff --git a/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponseTypes.ts b/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponseTypes.ts index 450e1601ca..55a222db08 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponseTypes.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponseTypes.ts @@ -1,4 +1,4 @@ -import { BigNumber } from '@ethersproject/bignumber'; +import { BigNumber } from '@moralisweb3/core'; import { EvmAddress, EvmAddressish } from '../EvmAddress'; import { EvmChain } from '../EvmChain'; import { EvmNative } from '../EvmNative'; diff --git a/packages/solApi/package.json b/packages/solApi/package.json index cab556913f..6825424c7b 100644 --- a/packages/solApi/package.json +++ b/packages/solApi/package.json @@ -29,7 +29,6 @@ "dependencies": { "@moralisweb3/api-utils": "^2.0.0-alpha.2", "@moralisweb3/core": "^2.0.0-alpha.2", - "@moralisweb3/sol-utils": "^2.0.0-alpha.2", - "ethers": "^5.6.2" + "@moralisweb3/sol-utils": "^2.0.0-alpha.2" } } diff --git a/packages/solUtils/package.json b/packages/solUtils/package.json index 915b4de01b..a88ea84a7f 100644 --- a/packages/solUtils/package.json +++ b/packages/solUtils/package.json @@ -30,8 +30,6 @@ "typescript": "^4.5.5" }, "dependencies": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/units": "^5.6.0", "@moralisweb3/core": "^2.0.0-alpha.2" } } diff --git a/packages/solUtils/src/dataTypes/SolNative/SolNative.ts b/packages/solUtils/src/dataTypes/SolNative/SolNative.ts index 779c4a81b0..ce785572f3 100644 --- a/packages/solUtils/src/dataTypes/SolNative/SolNative.ts +++ b/packages/solUtils/src/dataTypes/SolNative/SolNative.ts @@ -1,11 +1,21 @@ -import { BigNumber, BigNumberish, parseFixed } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { MoralisData, MoralisDataFormatted, CoreErrorCode, MoralisCoreError } from '@moralisweb3/core'; +import { + MoralisData, + MoralisDataFormatted, + CoreErrorCode, + MoralisCoreError, + BigNumberish, + BigNumber, +} from '@moralisweb3/core'; export type SolNativeUnit = 'solana' | 'lamports' | number; export type SolNativeish = SolNative | BigNumberish; +const unitToDecimals: Record = { + solana: 9, + lamports: 0, +}; + export class SolNative implements MoralisData { public static create(value: SolNativeish, unit?: SolNativeUnit): SolNative { if (value instanceof SolNative) { @@ -18,17 +28,15 @@ export class SolNative implements MoralisData { let decimal: number; if (typeof unit === 'number') { decimal = unit; - } else if (unit === 'lamports') { - decimal = 0; - } else if (unit === 'solana') { - decimal = 9; + } else if (unitToDecimals[unit] !== undefined) { + decimal = unitToDecimals[unit]; } else { throw new MoralisCoreError({ code: CoreErrorCode.INVALID_ARGUMENT, message: `Not supported Solana unit: ${unit}`, }); } - return parseFixed(value.toString(), decimal); + return BigNumber.from(value.toString(), decimal); } // TODO: we cannot share an internal instance of BigNumber, because BigNumber is located in @ethersproject. @@ -42,7 +50,7 @@ export class SolNative implements MoralisData { } public get solana(): string { - return formatUnits(this.rawValue, 9); + return this.rawValue.toDecimal(unitToDecimals['solana']); } public get lamports(): string { diff --git a/yarn.lock b/yarn.lock index fd59cd6d9b..255eba8c0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -671,46 +671,7 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@ethersproject/abi@5.6.4", "@ethersproject/abi@^5.6.3": - version "5.6.4" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.6.4.tgz#f6e01b6ed391a505932698ecc0d9e7a99ee60362" - integrity sha512-TTeZUlCeIHG6527/2goZA6gW5F8Emoc7MrZDC7hhP84aRGvW3TEdTnZR08Ls88YXM1m2SuK42Osw/jSi3uO8gg== - dependencies: - "@ethersproject/address" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/hash" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.1" - -"@ethersproject/abstract-provider@5.6.1", "@ethersproject/abstract-provider@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.6.1.tgz#02ddce150785caf0c77fe036a0ebfcee61878c59" - integrity sha512-BxlIgogYJtp1FS8Muvj8YfdClk3unZH0vRMVX791Z9INBNT/kuACZ9GzaY1Y4yFq+YSy6/w4gzj3HCRKrK9hsQ== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/networks" "^5.6.3" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/transactions" "^5.6.2" - "@ethersproject/web" "^5.6.1" - -"@ethersproject/abstract-signer@5.6.2", "@ethersproject/abstract-signer@^5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.6.2.tgz#491f07fc2cbd5da258f46ec539664713950b0b33" - integrity sha512-n1r6lttFBG0t2vNiI3HoWaS/KdOt8xyDjzlP2cuevlWLG6EX0OwcKLyG/Kp/cuwNxdy/ous+R/DEMdTUwWQIjQ== - dependencies: - "@ethersproject/abstract-provider" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - -"@ethersproject/address@5.6.1", "@ethersproject/address@^5.6.0", "@ethersproject/address@^5.6.1": +"@ethersproject/address@^5.6.0", "@ethersproject/address@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.1.tgz#ab57818d9aefee919c5721d28cd31fd95eff413d" integrity sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q== @@ -721,22 +682,7 @@ "@ethersproject/logger" "^5.6.0" "@ethersproject/rlp" "^5.6.1" -"@ethersproject/base64@5.6.1", "@ethersproject/base64@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.6.1.tgz#2c40d8a0310c9d1606c2c37ae3092634b41d87cb" - integrity sha512-qB76rjop6a0RIYYMiB4Eh/8n+Hxu2NIZm8S/Q7kNo5pmZfXhHGHmS4MinUainiBC54SCyRnwzL+KZjj8zbsSsw== - dependencies: - "@ethersproject/bytes" "^5.6.1" - -"@ethersproject/basex@5.6.1", "@ethersproject/basex@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.6.1.tgz#badbb2f1d4a6f52ce41c9064f01eab19cc4c5305" - integrity sha512-a52MkVz4vuBXR06nvflPMotld1FJWSj2QT0985v7P/emPZO00PucFAkbcmq2vpVU7Ts7umKiSI6SppiLykVWsA== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/properties" "^5.6.0" - -"@ethersproject/bignumber@5.6.2", "@ethersproject/bignumber@^5.6.0", "@ethersproject/bignumber@^5.6.2": +"@ethersproject/bignumber@^5.6.0", "@ethersproject/bignumber@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.2.tgz#72a0717d6163fab44c47bcc82e0c550ac0315d66" integrity sha512-v7+EEUbhGqT3XJ9LMPsKvXYHFc8eHxTowFCG/HgJErmq4XHJ2WR7aeyICg3uTOAQ7Icn0GFHAohXEhxQHq4Ubw== @@ -745,88 +691,21 @@ "@ethersproject/logger" "^5.6.0" bn.js "^5.2.1" -"@ethersproject/bytes@5.6.1", "@ethersproject/bytes@^5.6.1": +"@ethersproject/bytes@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.1.tgz#24f916e411f82a8a60412344bf4a813b917eefe7" integrity sha512-NwQt7cKn5+ZE4uDn+X5RAXLp46E1chXoaMmrxAyA0rblpxz8t58lVkrHXoRIn0lz1joQElQ8410GqhTqMOwc6g== dependencies: "@ethersproject/logger" "^5.6.0" -"@ethersproject/constants@5.6.1", "@ethersproject/constants@^5.6.1": +"@ethersproject/constants@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.6.1.tgz#e2e974cac160dd101cf79fdf879d7d18e8cb1370" integrity sha512-QSq9WVnZbxXYFftrjSjZDUshp6/eKp6qrtdBtUCm0QxCV5z1fG/w3kdlcsjMCQuQHUnAclKoK7XpXMezhRDOLg== dependencies: "@ethersproject/bignumber" "^5.6.2" -"@ethersproject/contracts@5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.6.2.tgz#20b52e69ebc1b74274ff8e3d4e508de971c287bc" - integrity sha512-hguUA57BIKi6WY0kHvZp6PwPlWF87MCeB4B7Z7AbUpTxfFXFdn/3b0GmjZPagIHS+3yhcBJDnuEfU4Xz+Ks/8g== - dependencies: - "@ethersproject/abi" "^5.6.3" - "@ethersproject/abstract-provider" "^5.6.1" - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/transactions" "^5.6.2" - -"@ethersproject/hash@5.6.1", "@ethersproject/hash@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.6.1.tgz#224572ea4de257f05b4abf8ae58b03a67e99b0f4" - integrity sha512-L1xAHurbaxG8VVul4ankNX5HgQ8PNCTrnVXEiFnE9xoRnaUcgfD12tZINtDinSllxPLCtGwguQxJ5E6keE84pA== - dependencies: - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.1" - -"@ethersproject/hdnode@5.6.2", "@ethersproject/hdnode@^5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.6.2.tgz#26f3c83a3e8f1b7985c15d1db50dc2903418b2d2" - integrity sha512-tERxW8Ccf9CxW2db3WsN01Qao3wFeRsfYY9TCuhmG0xNpl2IO8wgXU3HtWIZ49gUWPggRy4Yg5axU0ACaEKf1Q== - dependencies: - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/basex" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/pbkdf2" "^5.6.1" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/sha2" "^5.6.1" - "@ethersproject/signing-key" "^5.6.2" - "@ethersproject/strings" "^5.6.1" - "@ethersproject/transactions" "^5.6.2" - "@ethersproject/wordlists" "^5.6.1" - -"@ethersproject/json-wallets@5.6.1", "@ethersproject/json-wallets@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.6.1.tgz#3f06ba555c9c0d7da46756a12ac53483fe18dd91" - integrity sha512-KfyJ6Zwz3kGeX25nLihPwZYlDqamO6pfGKNnVMWWfEVVp42lTfCZVXXy5Ie8IZTN0HKwAngpIPi7gk4IJzgmqQ== - dependencies: - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/hdnode" "^5.6.2" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/pbkdf2" "^5.6.1" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.1" - "@ethersproject/strings" "^5.6.1" - "@ethersproject/transactions" "^5.6.2" - aes-js "3.0.0" - scrypt-js "3.0.1" - -"@ethersproject/keccak256@5.6.1", "@ethersproject/keccak256@^5.6.1": +"@ethersproject/keccak256@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.6.1.tgz#b867167c9b50ba1b1a92bccdd4f2d6bd168a91cc" integrity sha512-bB7DQHCTRDooZZdL3lk9wpL0+XuG3XLGHLh3cePnybsO3V0rdCAOQGpn/0R3aODmnTOOkCATJiD2hnL+5bwthA== @@ -834,68 +713,19 @@ "@ethersproject/bytes" "^5.6.1" js-sha3 "0.8.0" -"@ethersproject/logger@5.6.0", "@ethersproject/logger@^5.6.0": +"@ethersproject/logger@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== -"@ethersproject/networks@5.6.4", "@ethersproject/networks@^5.6.3": - version "5.6.4" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.6.4.tgz#51296d8fec59e9627554f5a8a9c7791248c8dc07" - integrity sha512-KShHeHPahHI2UlWdtDMn2lJETcbtaJge4k7XSjDR9h79QTd6yQJmv6Cp2ZA4JdqWnhszAOLSuJEd9C0PRw7hSQ== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/pbkdf2@5.6.1", "@ethersproject/pbkdf2@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.6.1.tgz#f462fe320b22c0d6b1d72a9920a3963b09eb82d1" - integrity sha512-k4gRQ+D93zDRPNUfmduNKq065uadC2YjMP/CqwwX5qG6R05f47boq6pLZtV/RnC4NZAYOPH1Cyo54q0c9sshRQ== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/sha2" "^5.6.1" - -"@ethersproject/properties@5.6.0", "@ethersproject/properties@^5.6.0": +"@ethersproject/properties@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.6.0.tgz#38904651713bc6bdd5bdd1b0a4287ecda920fa04" integrity sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg== dependencies: "@ethersproject/logger" "^5.6.0" -"@ethersproject/providers@5.6.8": - version "5.6.8" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.6.8.tgz#22e6c57be215ba5545d3a46cf759d265bb4e879d" - integrity sha512-Wf+CseT/iOJjrGtAOf3ck9zS7AgPmr2fZ3N97r4+YXN3mBePTG2/bJ8DApl9mVwYL+RpYbNxMEkEp4mPGdwG/w== - dependencies: - "@ethersproject/abstract-provider" "^5.6.1" - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/base64" "^5.6.1" - "@ethersproject/basex" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/hash" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/networks" "^5.6.3" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.1" - "@ethersproject/rlp" "^5.6.1" - "@ethersproject/sha2" "^5.6.1" - "@ethersproject/strings" "^5.6.1" - "@ethersproject/transactions" "^5.6.2" - "@ethersproject/web" "^5.6.1" - bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/random@5.6.1", "@ethersproject/random@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.6.1.tgz#66915943981bcd3e11bbd43733f5c3ba5a790255" - integrity sha512-/wtPNHwbmng+5yi3fkipA8YBT59DdkGRoC2vWk09Dci/q5DlgnMkhIycjHlavrvrjJBkFjO/ueLyT+aUDfc4lA== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/rlp@5.6.1", "@ethersproject/rlp@^5.6.1": +"@ethersproject/rlp@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.1.tgz#df8311e6f9f24dcb03d59a2bac457a28a4fe2bd8" integrity sha512-uYjmcZx+DKlFUk7a5/W9aQVaoEC7+1MOBgNtvNg13+RnuUwT4F0zTovC0tmay5SmRslb29V1B7Y5KCri46WhuQ== @@ -903,16 +733,7 @@ "@ethersproject/bytes" "^5.6.1" "@ethersproject/logger" "^5.6.0" -"@ethersproject/sha2@5.6.1", "@ethersproject/sha2@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.6.1.tgz#211f14d3f5da5301c8972a8827770b6fd3e51656" - integrity sha512-5K2GyqcW7G4Yo3uenHegbXRPDgARpWUiXc6RiF7b6i/HXUoWlb7uCARh7BAHg7/qT/Q5ydofNwiZcim9qpjB6g== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - hash.js "1.1.7" - -"@ethersproject/signing-key@5.6.2", "@ethersproject/signing-key@^5.6.2": +"@ethersproject/signing-key@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.6.2.tgz#8a51b111e4d62e5a62aee1da1e088d12de0614a3" integrity sha512-jVbu0RuP7EFpw82vHcL+GP35+KaNruVAZM90GxgQnGqB6crhBqW/ozBfFvdeImtmb4qPko0uxXjn8l9jpn0cwQ== @@ -924,28 +745,7 @@ elliptic "6.5.4" hash.js "1.1.7" -"@ethersproject/solidity@5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.6.1.tgz#5845e71182c66d32e6ec5eefd041fca091a473e2" - integrity sha512-KWqVLkUUoLBfL1iwdzUVlkNqAUIFMpbbeH0rgCfKmJp0vFtY4AsaN91gHKo9ZZLkC4UOm3cI3BmMV4N53BOq4g== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/sha2" "^5.6.1" - "@ethersproject/strings" "^5.6.1" - -"@ethersproject/strings@5.6.1", "@ethersproject/strings@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.6.1.tgz#dbc1b7f901db822b5cafd4ebf01ca93c373f8952" - integrity sha512-2X1Lgk6Jyfg26MUnsHiT456U9ijxKUybz8IM1Vih+NJxYtXhmvKBcHOmvGqpFSVJ0nQ4ZCoIViR8XlRw1v/+Cw== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/transactions@5.6.2", "@ethersproject/transactions@^5.6.0", "@ethersproject/transactions@^5.6.2": +"@ethersproject/transactions@^5.6.0": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.6.2.tgz#793a774c01ced9fe7073985bb95a4b4e57a6370b" integrity sha512-BuV63IRPHmJvthNkkt9G70Ullx6AcM+SDc+a8Aw/8Yew6YwT51TcBKEp1P4oOQ/bP25I18JJr7rcFRgFtU9B2Q== @@ -960,7 +760,7 @@ "@ethersproject/rlp" "^5.6.1" "@ethersproject/signing-key" "^5.6.2" -"@ethersproject/units@5.6.1", "@ethersproject/units@^5.6.0": +"@ethersproject/units@^5.6.0": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.6.1.tgz#ecc590d16d37c8f9ef4e89e2005bda7ddc6a4e6f" integrity sha512-rEfSEvMQ7obcx3KWD5EWWx77gqv54K6BKiZzKxkQJqtpriVsICrktIQmKl8ReNToPeIYPnFHpXvKpi068YFZXw== @@ -969,49 +769,6 @@ "@ethersproject/constants" "^5.6.1" "@ethersproject/logger" "^5.6.0" -"@ethersproject/wallet@5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.6.2.tgz#cd61429d1e934681e413f4bc847a5f2f87e3a03c" - integrity sha512-lrgh0FDQPuOnHcF80Q3gHYsSUODp6aJLAdDmDV0xKCN/T7D99ta1jGVhulg3PY8wiXEngD0DfM0I2XKXlrqJfg== - dependencies: - "@ethersproject/abstract-provider" "^5.6.1" - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/hash" "^5.6.1" - "@ethersproject/hdnode" "^5.6.2" - "@ethersproject/json-wallets" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.1" - "@ethersproject/signing-key" "^5.6.2" - "@ethersproject/transactions" "^5.6.2" - "@ethersproject/wordlists" "^5.6.1" - -"@ethersproject/web@5.6.1", "@ethersproject/web@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.6.1.tgz#6e2bd3ebadd033e6fe57d072db2b69ad2c9bdf5d" - integrity sha512-/vSyzaQlNXkO1WV+RneYKqCJwualcUdx/Z3gseVovZP0wIlOFcCE1hkRhKBH8ImKbGQbMl9EAAyJFrJu7V0aqA== - dependencies: - "@ethersproject/base64" "^5.6.1" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.1" - -"@ethersproject/wordlists@5.6.1", "@ethersproject/wordlists@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.6.1.tgz#1e78e2740a8a21e9e99947e47979d72e130aeda1" - integrity sha512-wiPRgBpNbNwCQFoCr8bcWO8o5I810cqO6mkdtKfLKFlLxeCWcnzDi4Alu8iyNzlhYuS9npCwivMbRWF19dyblw== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/hash" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.1" - "@graphiql/toolkit@^0.4.4": version "0.4.5" resolved "https://registry.yarnpkg.com/@graphiql/toolkit/-/toolkit-0.4.5.tgz#9fb5020444712562eae9581724695c235f610836" @@ -2331,11 +2088,6 @@ add@^2.0.6: resolved "https://registry.yarnpkg.com/add/-/add-2.0.6.tgz#248f0a9f6e5a528ef2295dbeec30532130ae2235" integrity sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q== -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== - ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -2821,11 +2573,6 @@ bcryptjs@2.4.3: resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ== -bech32@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" - integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== - better-path-resolve@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/better-path-resolve/-/better-path-resolve-1.0.0.tgz#13a35a1104cdd48a7b74bf8758f96a1ee613f99d" @@ -4427,42 +4174,6 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -ethers@^5.6.2: - version "5.6.9" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.6.9.tgz#4e12f8dfcb67b88ae7a78a9519b384c23c576a4d" - integrity sha512-lMGC2zv9HC5EC+8r429WaWu3uWJUCgUCt8xxKCFqkrFuBDZXDYIdzDUECxzjf2BMF8IVBByY1EBoGSL3RTm8RA== - dependencies: - "@ethersproject/abi" "5.6.4" - "@ethersproject/abstract-provider" "5.6.1" - "@ethersproject/abstract-signer" "5.6.2" - "@ethersproject/address" "5.6.1" - "@ethersproject/base64" "5.6.1" - "@ethersproject/basex" "5.6.1" - "@ethersproject/bignumber" "5.6.2" - "@ethersproject/bytes" "5.6.1" - "@ethersproject/constants" "5.6.1" - "@ethersproject/contracts" "5.6.2" - "@ethersproject/hash" "5.6.1" - "@ethersproject/hdnode" "5.6.2" - "@ethersproject/json-wallets" "5.6.1" - "@ethersproject/keccak256" "5.6.1" - "@ethersproject/logger" "5.6.0" - "@ethersproject/networks" "5.6.4" - "@ethersproject/pbkdf2" "5.6.1" - "@ethersproject/properties" "5.6.0" - "@ethersproject/providers" "5.6.8" - "@ethersproject/random" "5.6.1" - "@ethersproject/rlp" "5.6.1" - "@ethersproject/sha2" "5.6.1" - "@ethersproject/signing-key" "5.6.2" - "@ethersproject/solidity" "5.6.1" - "@ethersproject/strings" "5.6.1" - "@ethersproject/transactions" "5.6.2" - "@ethersproject/units" "5.6.1" - "@ethersproject/wallet" "5.6.2" - "@ethersproject/web" "5.6.1" - "@ethersproject/wordlists" "5.6.1" - event-emitter@^0.3.5, event-emitter@~0.3.4: version "0.3.5" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" @@ -8281,12 +7992,7 @@ prettier@^1.19.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -prettier@^2.5.1, prettier@^2.6.2: - version "2.7.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== - -prettier@^2.7.1: +prettier@^2.5.1, prettier@^2.6.2, prettier@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== @@ -9030,11 +8736,6 @@ scheduler@^0.19.1: loose-envify "^1.1.0" object-assign "^4.1.1" -scrypt-js@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" - integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== - seek-bzip@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" @@ -10376,11 +10077,6 @@ write-file-atomic@^4.0.1: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@7.4.6: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== - ws@7.5.0: version "7.5.0" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.0.tgz#0033bafea031fb9df041b2026fc72a571ca44691" From 23710b2ee3d1a28498865c5a7a41248679c76834 Mon Sep 17 00:00:00 2001 From: b4rtaz Date: Tue, 26 Jul 2022 12:46:19 +0200 Subject: [PATCH 2/7] polishing. --- packages/core/package.json | 4 +- packages/core/src/Error/ErrorCode.ts | 2 + .../src/dataTypes/BigNumber/BigNumber.test.ts | 224 +++--------------- .../core/src/dataTypes/BigNumber/BigNumber.ts | 127 ++-------- .../BigNumber/BigNumberFormatter.test.ts | 46 ++++ .../dataTypes/BigNumber/BigNumberFormatter.ts | 53 +++++ .../BigNumber/BigNumberParser.test.ts | 91 +++++++ .../dataTypes/BigNumber/BigNumberParser.ts | 89 +++++++ .../core/src/dataTypes/BigNumber/index.ts | 1 + .../src/dataTypes/Erc20Value/Erc20Value.ts | 6 +- .../src/dataTypes/EvmNative/EvmNative.ts | 3 +- .../src/dataTypes/SolNative/SolNative.test.ts | 5 +- .../src/dataTypes/SolNative/SolNative.ts | 12 +- yarn.lock | 11 +- 14 files changed, 353 insertions(+), 321 deletions(-) create mode 100644 packages/core/src/dataTypes/BigNumber/BigNumberFormatter.test.ts create mode 100644 packages/core/src/dataTypes/BigNumber/BigNumberFormatter.ts create mode 100644 packages/core/src/dataTypes/BigNumber/BigNumberParser.test.ts create mode 100644 packages/core/src/dataTypes/BigNumber/BigNumberParser.ts diff --git a/packages/core/package.json b/packages/core/package.json index 5c10b62a12..0b742c06fd 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -26,9 +26,7 @@ "devDependencies": { "prettier": "^2.5.1", "typed-emitter": "^2.1.0", - "typescript": "^4.5.5", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/units": "^5.6.0" + "typescript": "^4.5.5" }, "dependencies": { "@xstate/fsm": "^2.0.0", diff --git a/packages/core/src/Error/ErrorCode.ts b/packages/core/src/Error/ErrorCode.ts index ea76302ccf..cc96706294 100644 --- a/packages/core/src/Error/ErrorCode.ts +++ b/packages/core/src/Error/ErrorCode.ts @@ -19,6 +19,8 @@ export enum CoreErrorCode { CONFIG_INVALID_VALUE = 'C0014', CONFIG_KEY_ALREADY_EXIST = 'C0015', + BIG_NUMBER_ERROR = 'C0500', + NOT_IMPLEMENTED = 'C9000', } diff --git a/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts b/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts index 4355d0d1b6..6aea18667f 100644 --- a/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts +++ b/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts @@ -1,206 +1,52 @@ -import { BigNumber as MoralisBigNumber } from './BigNumber'; -import { parseFixed, BigNumber as EthersBigNumber } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; +import { BigNumber } from './BigNumber'; describe('BigNumber', () => { - describe('from()', () => { - it('parses string', () => { - const parseMoralis = (value: string) => { - const v = MoralisBigNumber.from(value, 0); - return { - string: v.toString(), - json: v.toJSON(), - dec0: v.toDecimal(0), - dec18: v.toDecimal(18), - dec5: v.toDecimal(5), - }; - }; - const parseEthers = (value: string) => { - const v = parseFixed(value, 0); - return { - string: v.toString(), - json: v.toJSON().hex, - dec0: formatUnits(v, 0), - dec18: formatUnits(v, 18), - dec5: formatUnits(v, 5), - }; - }; - - function test( - parse: (value: string) => { string: string; json: string; dec18: string; dec5: string; dec0: string }, - ) { - const v = parse('1000000000000000000'); - expect(v.string).toEqual('1000000000000000000'); - expect(v.json).toEqual('0x0de0b6b3a7640000'); - expect(v.dec0).toEqual('1000000000000000000'); - expect(v.dec18).toEqual('1.0'); - expect(v.dec5).toEqual('10000000000000.0'); - } - - test(parseMoralis); - test(parseEthers); - }); - - it('parses hex', () => { - const parseHexMoralis = (value: string) => MoralisBigNumber.from(value).toString(); - const parseHexEthers = (value: string) => EthersBigNumber.from(value).toString(); - - function test(parseHex: (value: string) => string) { - expect(parseHex('0x1')).toEqual('1'); - expect(parseHex('0x100')).toEqual('256'); - expect(parseHex('0x0')).toEqual('0'); - expect(parseHex('-0x0')).toEqual('0'); - expect(parseHex('-0x100')).toEqual('-256'); - } - - test(parseHexMoralis); - test(parseHexEthers); - }); + it('from() returns integer', () => { + const value = BigNumber.from('1000000000000000000'); + expect(value.toString()).toEqual('1000000000000000000'); + expect(value.toJSON()).toEqual('0x0de0b6b3a7640000'); + expect(value.toDecimal(0)).toEqual('1000000000000000000'); + expect(value.toDecimal(18)).toEqual('1.0'); + expect(value.toDecimal(5)).toEqual('10000000000000.0'); + expect(value.toBigInt()).toEqual(BigInt('1000000000000000000')); + }); - it('parses decimal', () => { - const parseMoralis = (value: string, decimals: number) => MoralisBigNumber.from(value, decimals).toString(); - const parseEthers = (value: string, decimals: number) => parseFixed(value, decimals).toString(); + it('fromDecimal() returns integer', () => { + const value = BigNumber.fromDecimal('1.1', 18); + expect(value.toString()).toEqual('1100000000000000000'); + expect(value.toJSON()).toEqual('0x0f43fc2c04ee0000'); + expect(value.toDecimal(0)).toEqual('1100000000000000000'); + expect(value.toDecimal(18)).toEqual('1.1'); + expect(value.toDecimal(5)).toEqual('11000000000000.0'); + }); - function test(parse: (value: string, decimal: number) => string) { - expect(parse('0', 0)).toEqual('0'); - expect(parse('0.0', 1)).toEqual('0'); - expect(parse('0.0', 6)).toEqual('0'); - expect(parse('0.1', 1)).toEqual('1'); - expect(parse('-0.1', 1)).toEqual('-1'); - expect(parse('-0.01', 2)).toEqual('-1'); - expect(parse('0.1', 2)).toEqual('10'); - expect(parse('0.1', 4)).toEqual('1000'); - expect(parse('1', 2)).toEqual('100'); - expect(parse('-1', 2)).toEqual('-100'); - expect(parse('-25', 2)).toEqual('-2500'); - expect(parse('999', 0)).toEqual('999'); - expect(parse('999', 2)).toEqual('99900'); - expect(parse('1.1', 18)).toEqual('1100000000000000000'); - expect(parse('25.12345', 18)).toEqual('25123450000000000000'); - expect(parse('-25.12345', 18)).toEqual('-25123450000000000000'); - expect(parse('0.128', 18)).toEqual('128000000000000000'); - } + it('does not create a new instance if BigNumber instance passed', () => { + const value = BigNumber.from(0x1); + expect(BigNumber.from(value) === value).toBe(true); + }); - test(parseMoralis); - test(parseEthers); - }); + describe('math', () => { + const from = (value: number) => BigNumber.from(value); - it('throws an error when fractional part is wrong', () => { - const expectedError = 'value has too long fractional part'; - expect(() => MoralisBigNumber.from('0.0', 0)).toThrowError(expectedError); - expect(() => MoralisBigNumber.from('0.0001', 1)).toThrowError(expectedError); - expect(() => MoralisBigNumber.from('0.0000001', 4)).toThrowError(expectedError); - expect(() => MoralisBigNumber.from('0.1', 0)).toThrowError(expectedError); - expect(() => MoralisBigNumber.from('-0.1', 0)).toThrowError(expectedError); + it('add() multiplies correctly', () => { + expect(from(2).add(from(3)).toString()).toEqual('5'); }); - it('throws an error when decimals is negative', () => { - expect(() => MoralisBigNumber.from('1', -1)).toThrowError('invalid decimal'); + it('sub() subtracts correctly', () => { + expect(from(10).sub(from(4)).toString()).toEqual('6'); }); - it('does not create a new instance if BigNumber instance passed', () => { - const value = MoralisBigNumber.from(0x1); - - expect(MoralisBigNumber.from(value) === value).toBe(true); + it('mul() multiplies correctly', () => { + expect(from(2).mul(from(3)).toString()).toEqual('6'); }); - }); - - describe('toDecimal()', () => { - it('returns correct decimals', () => { - const toDecimalMoralis = (value: string, decimals: number) => MoralisBigNumber.from(value).toDecimal(decimals); - const toDecimalEthers = (value: string, decimals: number) => formatUnits(value, decimals); - - function test(toDecimal: (value: string, decimals: number) => string) { - expect(toDecimal('0', 0)).toEqual('0'); - expect(toDecimal('-0', 0)).toEqual('0'); - expect(toDecimal('0', 2)).toEqual('0.0'); - expect(toDecimal('-0', 2)).toEqual('0.0'); - expect(toDecimal('0', 10)).toEqual('0.0'); - expect(toDecimal('-256', 0)).toEqual('-256'); - expect(toDecimal('256', 0)).toEqual('256'); - expect(toDecimal('256', 1)).toEqual('25.6'); - expect(toDecimal('-256', 1)).toEqual('-25.6'); - expect(toDecimal('256', 2)).toEqual('2.56'); - expect(toDecimal('256', 5)).toEqual('0.00256'); - expect(toDecimal('256', 10)).toEqual('0.0000000256'); - expect(toDecimal('-256', 10)).toEqual('-0.0000000256'); - expect(toDecimal('256', 18)).toEqual('0.000000000000000256'); - expect(toDecimal('-256', 18)).toEqual('-0.000000000000000256'); - } - test(toDecimalMoralis); - test(toDecimalEthers); + it('div() divides correctly', () => { + expect(from(15).div(from(5)).toString()).toEqual('3'); }); - it('throws an error if decimals is negative', () => { - expect(() => MoralisBigNumber.from(0).toDecimal(-1)).toThrowError('invalid decimals'); + it('eq() returns correct value', () => { + expect(from(1).eq(from(1))).toBe(true); + expect(from(1).eq(from(-1))).toBe(false); }); }); - - it('parses integers', () => { - const parseMoralis = (value: number, decimals: number) => MoralisBigNumber.from(value, decimals).toString(); - const parseEthers = (value: number, decimals: number) => parseFixed(value.toString(), decimals).toString(); - - function test(parse: (value: number, decimals: number) => string) { - expect(parse(0, 0)).toEqual('0'); - expect(parse(10, 0)).toEqual('10'); - expect(parse(-10, 0)).toEqual('-10'); - expect(parse(128, 0)).toEqual('128'); - expect(parse(128, 5)).toEqual('12800000'); - expect(parse(128, 0)).toEqual('128'); - expect(parse(128, 1)).toEqual('1280'); - expect(parse(-128, 1)).toEqual('-1280'); - expect(parse(-128, 10)).toEqual('-1280000000000'); - } - - test(parseMoralis); - test(parseEthers); - }); - - it('eq() returns correct value', () => { - expect(MoralisBigNumber.from(1).eq(MoralisBigNumber.from(1))).toBe(true); - expect(MoralisBigNumber.from(1).eq(MoralisBigNumber.from(-1))).toBe(false); - }); - - it('throws an error when NaN passed', () => { - expect(() => MoralisBigNumber.from(NaN)).toThrowError('The number NaN cannot be converted to a BigInt'); - }); - - it('throws an error when invalid string passed', () => { - function test(input: string, expectedError: string = 'Cannot convert') { - expect(() => MoralisBigNumber.from(input)).toThrowError(expectedError); - } - - test('lorem ipsum'); - test('-x'); - test('x'); - test('##'); - test('$$'); - test('!'); - test('..', 'value has more than one dot'); - test('.', 'value has empty fragments'); - test('', 'value has empty fragments'); - test('-', 'value has empty fragments'); - }); - - it('toHex() returns correct values', () => { - const toHexMoralis = (value: string) => MoralisBigNumber.from(value).toHex(); - const toHexEthers = (value: string) => parseFixed(value).toHexString(); - - function test(toHex: (value: string) => string) { - expect(toHex('10')).toEqual('0x0a'); - expect(toHex('200')).toEqual('0xc8'); - expect(toHex('0')).toEqual('0x00'); - expect(toHex('351')).toEqual('0x015f'); - expect(toHex('123456789')).toEqual('0x075bcd15'); - expect(toHex('-0')).toEqual('0x00'); - expect(toHex('0')).toEqual('0x00'); - expect(toHex('-100')).toEqual('-0x64'); - expect(toHex('-1')).toEqual('-0x01'); - expect(toHex('-123456789')).toEqual('-0x075bcd15'); - } - - test(toHexMoralis); - test(toHexEthers); - }); }); diff --git a/packages/core/src/dataTypes/BigNumber/BigNumber.ts b/packages/core/src/dataTypes/BigNumber/BigNumber.ts index 24cc608d1c..1f7b71a04b 100644 --- a/packages/core/src/dataTypes/BigNumber/BigNumber.ts +++ b/packages/core/src/dataTypes/BigNumber/BigNumber.ts @@ -1,83 +1,40 @@ -function getMultiplier(decimals: number): bigint { - if (decimals < 0) { - throw new Error('BigNumber: invalid decimals'); - } - // decimals = 0, multiplier = 1 - // decimals = 1, multiplier = 10 - // decimals = 2, multiplier = 100 - // ... - const ten = BigInt(10); - let multiplier = BigInt(1); - while (decimals-- > 0) { - multiplier *= ten; - } - return multiplier; -} +import { BigNumberFormatter } from './BigNumberFormatter'; +import { BigNumberParser, BigNumberPrimitive } from './BigNumberParser'; -export type BigNumberPrimitive = number | string | bigint; export type BigNumberish = BigNumber | BigNumberPrimitive; export class BigNumber { - public static from(value: BigNumberish, decimals = 0): BigNumber { + public static from(value: BigNumberish): BigNumber { if (value instanceof BigNumber) { return value; } - return new BigNumber(BigNumber.parse(value, decimals)); + return new BigNumber(BigNumberParser.parseInt(value)); } - private static parse(value: BigNumberPrimitive, decimals: number): bigint { - if (typeof value !== 'string') { - return BigInt(value) * getMultiplier(decimals); - } - return BigNumber.parseString(value, decimals); + public static fromDecimal(value: BigNumberPrimitive, decimals = 0): BigNumber { + return new BigNumber(BigNumberParser.parseDecimal(value, decimals)); } - private static parseString(value: string, decimals: number): bigint { - const isNegative = value.startsWith('-'); - if (isNegative) { - value = value.substring(1); - } - - const fragments = value.startsWith('0x') ? [value] : value.split('.'); - if (fragments.length > 2) { - throw new Error('BigNumber: value has more than one dot'); - } - if (fragments.some((fragment) => !fragment)) { - throw new Error('BigNumber: value has empty fragments'); - } - - const multiplier = getMultiplier(decimals); - let result: bigint; + private constructor(private readonly value: bigint) {} - if (fragments.length === 1) { - result = BigInt(fragments[0]) * multiplier; - } else { - const whole = fragments[0]; - let fraction = fragments[1]; - if (fraction.length > decimals) { - throw new Error(`BigNumber: value has too long fractional part: ${fraction.length}, max: ${decimals}`); - } - if (fraction.length < decimals) { - fraction = fraction.padEnd(decimals, '0'); - } - - result = BigInt(whole) * multiplier + BigInt(fraction); - } - - if (isNegative) { - result *= BigInt(-1); - } - return result; + public toBigInt(): bigint { + return this.value; } - public constructor(private readonly value: bigint) {} + public add(value: BigNumberish): BigNumber { + return new BigNumber(this.value + asBigInt(value)); + } - public toBigInt(): bigint { - return this.value; + public sub(value: BigNumberish): BigNumber { + return new BigNumber(this.value - asBigInt(value)); } public mul(value: BigNumberish): BigNumber { - return new BigNumber(this.value * BigNumber.from(value).toBigInt()); + return new BigNumber(this.value * asBigInt(value)); + } + + public div(value: BigNumberish): BigNumber { + return new BigNumber(this.value / asBigInt(value)); } public eq(value: BigNumber): boolean { @@ -85,33 +42,7 @@ export class BigNumber { } public toDecimal(decimals: number): string { - if (decimals < 0) { - throw new Error('BigNumber: invalid decimals'); - } - let result = this.value.toString(); - if (decimals === 0) { - return result; - } - - const isNegative = result.startsWith('-'); - if (isNegative) { - result = result.substring(1); - } - result = result.padStart(decimals, '0'); - - const dot = result.length - decimals; - const whole = dot === 0 ? '0' : result.substring(0, dot); - const fraction = result.substring(dot); - - result = whole + '.' + fraction; - - while (result[result.length - 1] === '0' && result[result.length - 2] !== '.') { - result = result.substring(0, result.length - 1); - } - if (isNegative) { - result = '-' + result; - } - return result; + return BigNumberFormatter.toDecimal(this.value, decimals); } public toString(): string { @@ -119,22 +50,14 @@ export class BigNumber { } public toHex(): string { - let result = this.value.toString(16); - const isNegative = result.startsWith('-'); - if (isNegative) { - result = result.substring(1); - } - if (result.length % 2 !== 0) { - result = '0' + result; - } - result = '0x' + result; - if (isNegative) { - result = '-' + result; - } - return result; + return BigNumberFormatter.toHex(this.value); } public toJSON(): string { return this.toHex(); } } + +function asBigInt(value: BigNumberish): bigint { + return BigNumber.from(value).toBigInt(); +} diff --git a/packages/core/src/dataTypes/BigNumber/BigNumberFormatter.test.ts b/packages/core/src/dataTypes/BigNumber/BigNumberFormatter.test.ts new file mode 100644 index 0000000000..c935bc97d0 --- /dev/null +++ b/packages/core/src/dataTypes/BigNumber/BigNumberFormatter.test.ts @@ -0,0 +1,46 @@ +import { BigNumberFormatter } from './BigNumberFormatter'; + +describe('BigNumberFormatter', () => { + describe('toDecimal()', () => { + const toDecimal = (value: string, decimals: number) => BigNumberFormatter.toDecimal(BigInt(value), decimals); + + it('returns correct value', () => { + expect(toDecimal('0', 0)).toEqual('0'); + expect(toDecimal('-0', 0)).toEqual('0'); + expect(toDecimal('0', 2)).toEqual('0.0'); + expect(toDecimal('-0', 2)).toEqual('0.0'); + expect(toDecimal('0', 10)).toEqual('0.0'); + expect(toDecimal('-256', 0)).toEqual('-256'); + expect(toDecimal('256', 0)).toEqual('256'); + expect(toDecimal('256', 1)).toEqual('25.6'); + expect(toDecimal('-256', 1)).toEqual('-25.6'); + expect(toDecimal('256', 2)).toEqual('2.56'); + expect(toDecimal('256', 5)).toEqual('0.00256'); + expect(toDecimal('256', 10)).toEqual('0.0000000256'); + expect(toDecimal('-256', 10)).toEqual('-0.0000000256'); + expect(toDecimal('256', 18)).toEqual('0.000000000000000256'); + expect(toDecimal('-256', 18)).toEqual('-0.000000000000000256'); + }); + + it('throws an error if decimals is negative', () => { + expect(() => toDecimal('0', -1)).toThrowError('Invalid decimals'); + }); + }); + + describe('toHex()', () => { + const toHex = (value: string) => BigNumberFormatter.toHex(BigInt(value)); + + it('returns correct value', () => { + expect(toHex('10')).toEqual('0x0a'); + expect(toHex('200')).toEqual('0xc8'); + expect(toHex('0')).toEqual('0x00'); + expect(toHex('351')).toEqual('0x015f'); + expect(toHex('123456789')).toEqual('0x075bcd15'); + expect(toHex('-0')).toEqual('0x00'); + expect(toHex('0')).toEqual('0x00'); + expect(toHex('-100')).toEqual('-0x64'); + expect(toHex('-1')).toEqual('-0x01'); + expect(toHex('-123456789')).toEqual('-0x075bcd15'); + }); + }); +}); diff --git a/packages/core/src/dataTypes/BigNumber/BigNumberFormatter.ts b/packages/core/src/dataTypes/BigNumber/BigNumberFormatter.ts new file mode 100644 index 0000000000..cda79a132c --- /dev/null +++ b/packages/core/src/dataTypes/BigNumber/BigNumberFormatter.ts @@ -0,0 +1,53 @@ +import { CoreErrorCode, MoralisCoreError } from '../../Error'; + +export class BigNumberFormatter { + public static toDecimal(value: bigint, decimals: number): string { + if (decimals < 0) { + throw new MoralisCoreError({ + code: CoreErrorCode.BIG_NUMBER_ERROR, + message: 'Invalid decimals', + }); + } + + let result = value.toString(); + if (decimals === 0) { + return result; + } + + const isNegative = result.startsWith('-'); + if (isNegative) { + result = result.substring(1); + } + result = result.padStart(decimals, '0'); + + const dot = result.length - decimals; + const whole = dot === 0 ? '0' : result.substring(0, dot); + const fraction = result.substring(dot); + + result = whole + '.' + fraction; + + while (result[result.length - 1] === '0' && result[result.length - 2] !== '.') { + result = result.substring(0, result.length - 1); + } + if (isNegative) { + result = '-' + result; + } + return result; + } + + public static toHex(value: bigint): string { + let result = value.toString(16); + const isNegative = result.startsWith('-'); + if (isNegative) { + result = result.substring(1); + } + if (result.length % 2 !== 0) { + result = '0' + result; + } + result = '0x' + result; + if (isNegative) { + result = '-' + result; + } + return result; + } +} diff --git a/packages/core/src/dataTypes/BigNumber/BigNumberParser.test.ts b/packages/core/src/dataTypes/BigNumber/BigNumberParser.test.ts new file mode 100644 index 0000000000..8a458caee7 --- /dev/null +++ b/packages/core/src/dataTypes/BigNumber/BigNumberParser.test.ts @@ -0,0 +1,91 @@ +import { BigNumberParser, BigNumberPrimitive } from './BigNumberParser'; + +describe('BigNumberParser', () => { + describe('parseInt()', () => { + const parseInt = (value: BigNumberPrimitive) => BigNumberParser.parseInt(value).toString(); + + it('returns correct value', () => { + expect(parseInt(0)).toEqual('0'); + expect(parseInt(10)).toEqual('10'); + expect(parseInt(-10)).toEqual('-10'); + expect(parseInt('100')).toEqual('100'); + expect(parseInt('-100')).toEqual('-100'); + expect(parseInt('0x1')).toEqual('1'); + expect(parseInt('0x0')).toEqual('0'); + expect(parseInt('-0x0')).toEqual('0'); + expect(parseInt('0x100')).toEqual('256'); + expect(parseInt('-0x100')).toEqual('-256'); + expect(parseInt('0')).toEqual('0'); + expect(parseInt('-0')).toEqual('0'); + expect(parseInt(BigInt(10))).toEqual('10'); + expect(parseInt(10)).toEqual('10'); + }); + + it('throws an error when NaN passed', () => { + expect(() => parseInt(NaN)).toThrowError('The number NaN cannot be converted to a BigInt'); + }); + }); + + describe('parseDecimal()', () => { + const parseDecimal = (value: BigNumberPrimitive, decimals: number) => + BigNumberParser.parseDecimal(value, decimals).toString(); + + it('returns correct value', () => { + expect(parseDecimal('0', 0)).toEqual('0'); + expect(parseDecimal('0.0', 1)).toEqual('0'); + expect(parseDecimal('0.0', 6)).toEqual('0'); + expect(parseDecimal('0.1', 1)).toEqual('1'); + expect(parseDecimal('-0.1', 1)).toEqual('-1'); + expect(parseDecimal('-0.01', 2)).toEqual('-1'); + expect(parseDecimal('0.1', 2)).toEqual('10'); + expect(parseDecimal('0.1', 4)).toEqual('1000'); + expect(parseDecimal('1', 2)).toEqual('100'); + expect(parseDecimal('-1', 2)).toEqual('-100'); + expect(parseDecimal('-25', 2)).toEqual('-2500'); + expect(parseDecimal('999', 0)).toEqual('999'); + expect(parseDecimal('999', 2)).toEqual('99900'); + expect(parseDecimal('1.1', 18)).toEqual('1100000000000000000'); + expect(parseDecimal('25.12345', 18)).toEqual('25123450000000000000'); + expect(parseDecimal('-25.12345', 18)).toEqual('-25123450000000000000'); + expect(parseDecimal('0.128', 18)).toEqual('128000000000000000'); + expect(parseDecimal('0x0', 0)).toEqual('0'); + expect(parseDecimal('-0x0', 0)).toEqual('0'); + expect(parseDecimal('0x100', 0)).toEqual('256'); + expect(parseDecimal('-0x100', 0)).toEqual('-256'); + expect(parseDecimal(1, 0)).toEqual('1'); + expect(parseDecimal(1, 5)).toEqual('100000'); + expect(parseDecimal(BigInt(1), 0)).toEqual('1'); + expect(parseDecimal(BigInt(1), 5)).toEqual('100000'); + }); + + it('throws an error when invalid string passed', () => { + function test(input: string, expectedError: string = 'Cannot convert') { + expect(() => parseDecimal(input, 0)).toThrowError(expectedError); + } + + test('lorem ipsum'); + test('-x'); + test('x'); + test('##'); + test('$$'); + test('!'); + test('..', 'Value has more than one dot'); + test('.', 'Value has empty fragments'); + test('', 'Value has empty fragments'); + test('-', 'Value has empty fragments'); + }); + + it('throws an error when fractional part is wrong', () => { + const expectedError = 'Value has too long fractional part'; + expect(() => parseDecimal('0.0', 0)).toThrowError(expectedError); + expect(() => parseDecimal('0.0001', 1)).toThrowError(expectedError); + expect(() => parseDecimal('0.0000001', 4)).toThrowError(expectedError); + expect(() => parseDecimal('0.1', 0)).toThrowError(expectedError); + expect(() => parseDecimal('-0.1', 0)).toThrowError(expectedError); + }); + + it('throws an error when decimals is negative', () => { + expect(() => parseDecimal('1', -1)).toThrowError('Invalid decimal'); + }); + }); +}); diff --git a/packages/core/src/dataTypes/BigNumber/BigNumberParser.ts b/packages/core/src/dataTypes/BigNumber/BigNumberParser.ts new file mode 100644 index 0000000000..026d5b7944 --- /dev/null +++ b/packages/core/src/dataTypes/BigNumber/BigNumberParser.ts @@ -0,0 +1,89 @@ +import { CoreErrorCode, MoralisCoreError } from '../../Error'; + +export type BigNumberPrimitive = number | string | bigint; + +export class BigNumberParser { + public static parseInt(value: BigNumberPrimitive): bigint { + if (typeof value === 'string') { + const isNegativeHex = value.startsWith('-0x'); + if (isNegativeHex) { + value = value.substring(1); + } + let result = BigInt(value); + if (isNegativeHex) { + result *= BigInt(-1); + } + return result; + } + return BigInt(value); + } + + public static parseDecimal(value: BigNumberPrimitive, decimals: number): bigint { + const multiplier = getMultiplier(decimals); + + if (typeof value === 'number') { + return BigInt(value) * multiplier; + } + if (typeof value === 'bigint') { + return value * multiplier; + } + + const isNegative = value.startsWith('-'); + if (isNegative) { + value = value.substring(1); + } + + const fragments = value.split('.'); + if (fragments.length > 2) { + throw createError('Value has more than one dot'); + } + if (fragments.some((fragment) => !fragment)) { + throw createError('Value has empty fragments'); + } + + let result: bigint; + + if (fragments.length === 1) { + result = BigInt(fragments[0]) * multiplier; + } else { + const whole = fragments[0]; + let fraction = fragments[1]; + if (fraction.length > decimals) { + throw createError(`Value has too long fractional part: ${fraction.length}, max: ${decimals}`); + } + if (fraction.length < decimals) { + fraction = fraction.padEnd(decimals, '0'); + } + + result = BigInt(whole) * multiplier + BigInt(fraction); + } + + if (isNegative) { + result *= BigInt(-1); + } + return result; + } +} + +function getMultiplier(decimals: number): bigint { + if (decimals < 0) { + throw createError('Invalid decimals'); + } + // decimals = 0, multiplier = 1 + // decimals = 1, multiplier = 10 + // decimals = 2, multiplier = 100 + // ... + const ten = BigInt(10); + let multiplier = BigInt(1); + while (decimals-- > 0) { + multiplier *= ten; + } + return multiplier; +} + +function createError(message: string): Error { + return new MoralisCoreError({ + code: CoreErrorCode.BIG_NUMBER_ERROR, + message, + }); +} diff --git a/packages/core/src/dataTypes/BigNumber/index.ts b/packages/core/src/dataTypes/BigNumber/index.ts index f2773ccedc..2044f020c1 100644 --- a/packages/core/src/dataTypes/BigNumber/index.ts +++ b/packages/core/src/dataTypes/BigNumber/index.ts @@ -1 +1,2 @@ export * from './BigNumber'; +export { BigNumberPrimitive } from './BigNumberParser'; diff --git a/packages/evmUtils/src/dataTypes/Erc20Value/Erc20Value.ts b/packages/evmUtils/src/dataTypes/Erc20Value/Erc20Value.ts index 2f0ae29c0d..0211f48641 100644 --- a/packages/evmUtils/src/dataTypes/Erc20Value/Erc20Value.ts +++ b/packages/evmUtils/src/dataTypes/Erc20Value/Erc20Value.ts @@ -1,6 +1,4 @@ -import { BigNumberish } from '@ethersproject/bignumber'; -import { parseUnits } from '@ethersproject/units'; -import { MoralisData } from '@moralisweb3/core'; +import { BigNumber, BigNumberish, MoralisData } from '@moralisweb3/core'; const EVM_ERC20_DEFAULT_DECIMALS = 18; @@ -60,7 +58,7 @@ export class Erc20Value implements MoralisData { } get value() { - return parseUnits(this._value.amount.toString(), this._value.decimals); + return BigNumber.fromDecimal(this._value.amount.toString(), this._value.decimals); } toString() { diff --git a/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts b/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts index a8f1404e63..be830538f3 100644 --- a/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts +++ b/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts @@ -48,8 +48,7 @@ export class EvmNative implements MoralisData { decimals = unitToDecimals[unit]; } - const value = BigNumber.from(native, decimals); - return value; + return BigNumber.fromDecimal(native.toString(), decimals); } public static equals(valueA: EvmNativeish, valueB: EvmNativeish): boolean { diff --git a/packages/solUtils/src/dataTypes/SolNative/SolNative.test.ts b/packages/solUtils/src/dataTypes/SolNative/SolNative.test.ts index dfd8ded752..e15db0ba97 100644 --- a/packages/solUtils/src/dataTypes/SolNative/SolNative.test.ts +++ b/packages/solUtils/src/dataTypes/SolNative/SolNative.test.ts @@ -1,3 +1,4 @@ +import { BigNumber } from '@moralisweb3/core'; import { SolNative, SolNativeish, SolNativeUnit } from './SolNative'; describe('SolNative', () => { @@ -47,7 +48,7 @@ describe('SolNative', () => { expect(v10b.equals(v20)).toBe(false); }); - it('value() is not implemented :-)', () => { - expect(() => SolNative.create(1).value).toThrowError('Not implemented'); + it('value is instance of BigNumber', () => { + expect(SolNative.create(1).value).toBeInstanceOf(BigNumber); }); }); diff --git a/packages/solUtils/src/dataTypes/SolNative/SolNative.ts b/packages/solUtils/src/dataTypes/SolNative/SolNative.ts index ce785572f3..bff2406aa5 100644 --- a/packages/solUtils/src/dataTypes/SolNative/SolNative.ts +++ b/packages/solUtils/src/dataTypes/SolNative/SolNative.ts @@ -36,17 +36,11 @@ export class SolNative implements MoralisData { message: `Not supported Solana unit: ${unit}`, }); } - return BigNumber.from(value.toString(), decimal); + return BigNumber.fromDecimal(value.toString(), decimal); } - // TODO: we cannot share an internal instance of BigNumber, because BigNumber is located in @ethersproject. - // We should use some class from Solana JS stack. For example @solana/web3.js uses BN.js. - // Temporary we use BigNumber internally. - public get value(): unknown { - throw new MoralisCoreError({ - code: CoreErrorCode.NOT_IMPLEMENTED, - message: 'Not implemented', - }); + public get value(): BigNumber { + return this.rawValue; } public get solana(): string { diff --git a/yarn.lock b/yarn.lock index 255eba8c0e..2ad657f8b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -682,7 +682,7 @@ "@ethersproject/logger" "^5.6.0" "@ethersproject/rlp" "^5.6.1" -"@ethersproject/bignumber@^5.6.0", "@ethersproject/bignumber@^5.6.2": +"@ethersproject/bignumber@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.2.tgz#72a0717d6163fab44c47bcc82e0c550ac0315d66" integrity sha512-v7+EEUbhGqT3XJ9LMPsKvXYHFc8eHxTowFCG/HgJErmq4XHJ2WR7aeyICg3uTOAQ7Icn0GFHAohXEhxQHq4Ubw== @@ -760,15 +760,6 @@ "@ethersproject/rlp" "^5.6.1" "@ethersproject/signing-key" "^5.6.2" -"@ethersproject/units@^5.6.0": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.6.1.tgz#ecc590d16d37c8f9ef4e89e2005bda7ddc6a4e6f" - integrity sha512-rEfSEvMQ7obcx3KWD5EWWx77gqv54K6BKiZzKxkQJqtpriVsICrktIQmKl8ReNToPeIYPnFHpXvKpi068YFZXw== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@graphiql/toolkit@^0.4.4": version "0.4.5" resolved "https://registry.yarnpkg.com/@graphiql/toolkit/-/toolkit-0.4.5.tgz#9fb5020444712562eae9581724695c235f610836" From cc62cbbe484365491dcc4dbfb36eb994762a2e0e Mon Sep 17 00:00:00 2001 From: b4rtaz Date: Tue, 26 Jul 2022 12:47:29 +0200 Subject: [PATCH 3/7] reverse settings.json. --- .vscode/settings.json | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 8f16b818b5..a03b4b5496 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,14 +3,5 @@ "search.exclude": { "**/.git": true, "**/node_modules": true - }, - "files.exclude": { - "**/.git": true, - "**/.svn": true, - "**/.hg": true, - "**/CVS": true, - "**/.DS_Store": true, - "**/Thumbs.db": true, - "**/node_modules": true } } From 459ff5e1d5c9c48309555bdd68e6ebbaf9c69a4b Mon Sep 17 00:00:00 2001 From: b4rtaz Date: Tue, 26 Jul 2022 12:56:19 +0200 Subject: [PATCH 4/7] one more test. --- packages/core/src/dataTypes/BigNumber/BigNumber.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts b/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts index 6aea18667f..88ecc5b1fb 100644 --- a/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts +++ b/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts @@ -20,6 +20,11 @@ describe('BigNumber', () => { expect(value.toDecimal(5)).toEqual('11000000000000.0'); }); + it('fromDecimal() assumes decimals=0 if not provided', () => { + const value = BigNumber.fromDecimal(100); + expect(value.toString()).toEqual('100'); + }); + it('does not create a new instance if BigNumber instance passed', () => { const value = BigNumber.from(0x1); expect(BigNumber.from(value) === value).toBe(true); From 1391e2a63197c4216abd89df0418fb627d99d66d Mon Sep 17 00:00:00 2001 From: b4rtaz Date: Tue, 26 Jul 2022 12:59:09 +0200 Subject: [PATCH 5/7] changeset. --- .changeset/brave-bats-destroy.md | 2 +- .changeset/config.json | 2 +- .changeset/itchy-nails-push.md | 2 +- .changeset/old-cherries-jam.md | 2 +- .changeset/young-buses-argue.md | 13 +++++++++++++ 5 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 .changeset/young-buses-argue.md diff --git a/.changeset/brave-bats-destroy.md b/.changeset/brave-bats-destroy.md index dcd40b1f70..1573458a5c 100644 --- a/.changeset/brave-bats-destroy.md +++ b/.changeset/brave-bats-destroy.md @@ -1,5 +1,5 @@ --- -'@moralisweb3/api': major +'@moralisweb3/api-utils': major '@moralisweb3/evm-api': major '@moralisweb3/integration': major --- diff --git a/.changeset/config.json b/.changeset/config.json index b3f861a91a..bfbc5f95be 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -6,7 +6,7 @@ [ "@moralisweb3/core", "@moralisweb3/auth", - "@moralisweb3/api", + "@moralisweb3/api-utils", "@moralisweb3/evm-utils", "@moralisweb3/evm-api", "@moralisweb3/sol-api" diff --git a/.changeset/itchy-nails-push.md b/.changeset/itchy-nails-push.md index fc6d3d357b..ec00ee823d 100644 --- a/.changeset/itchy-nails-push.md +++ b/.changeset/itchy-nails-push.md @@ -1,6 +1,6 @@ --- 'test-node': patch -'@moralisweb3/api': patch +'@moralisweb3/api-utils': patch '@moralisweb3/auth': patch '@moralisweb3/core': patch '@moralisweb3/evm-api': patch diff --git a/.changeset/old-cherries-jam.md b/.changeset/old-cherries-jam.md index 1658e24181..5e45f438df 100644 --- a/.changeset/old-cherries-jam.md +++ b/.changeset/old-cherries-jam.md @@ -1,5 +1,5 @@ --- -'@moralisweb3/api': major +'@moralisweb3/api-utils': major --- Generic logic for api modules diff --git a/.changeset/young-buses-argue.md b/.changeset/young-buses-argue.md new file mode 100644 index 0000000000..fe2ffa4177 --- /dev/null +++ b/.changeset/young-buses-argue.md @@ -0,0 +1,13 @@ +--- +'@moralisweb3/core': patch +'@moralisweb3/evm-api': patch +'@moralisweb3/evm-utils': patch +'@moralisweb3/sol-api': patch +'@moralisweb3/sol-utils': patch +'@moralisweb3/api-utils': patch +'@moralisweb3/auth': patch +'@moralisweb3/integration': patch +'moralis': patch +--- + +Replaced BigNumber from @ethersproject by own implementation. From 77c72820efc9d5e75018044667d43dc953613ae4 Mon Sep 17 00:00:00 2001 From: b4rtaz Date: Wed, 27 Jul 2022 11:11:33 +0200 Subject: [PATCH 6/7] polishing. --- packages/core/src/Config/MoralisConfig.ts | 6 +++--- .../src/dataTypes/BigNumber/BigNumber.test.ts | 16 ++++++++-------- .../core/src/dataTypes/BigNumber/BigNumber.ts | 6 +++--- .../src/resolvers/account/getTokenTransfers.ts | 2 +- .../src/resolvers/account/getTransactions.ts | 2 +- .../src/resolvers/token/getTokenAllowance.ts | 2 +- .../src/dataTypes/Erc20Value/Erc20Value.ts | 2 +- .../src/dataTypes/EvmNative/EvmNative.ts | 2 +- .../dataTypes/EvmTransaction/EvmTransaction.ts | 10 +++++----- .../EvmTransactionReceipt.test.ts | 2 +- .../EvmTransactionReceipt.ts | 6 +++--- .../EvmTransactionResponse.ts | 10 +++++----- 12 files changed, 33 insertions(+), 33 deletions(-) diff --git a/packages/core/src/Config/MoralisConfig.ts b/packages/core/src/Config/MoralisConfig.ts index 70e1cd3ff1..f37bd9c0c4 100644 --- a/packages/core/src/Config/MoralisConfig.ts +++ b/packages/core/src/Config/MoralisConfig.ts @@ -12,8 +12,8 @@ interface EvmUtilsConfigValues { formatEvmChainId: EvmChainIdFormat; } -// @moralisweb3/api -interface ApiConfigValues { +// @moralisweb3/api-utils +interface ApiUtilsConfigValues { apiKey: string; } @@ -30,7 +30,7 @@ interface SolApiConfigValues { export type MoralisConfigValues = | CoreConfigValues | EvmUtilsConfigValues - | ApiConfigValues + | ApiUtilsConfigValues | EvmApiConfigValues | SolApiConfigValues | { [key: string]: string | number }; // Other, not strong typed values. diff --git a/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts b/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts index 88ecc5b1fb..db460a773e 100644 --- a/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts +++ b/packages/core/src/dataTypes/BigNumber/BigNumber.test.ts @@ -1,8 +1,8 @@ import { BigNumber } from './BigNumber'; describe('BigNumber', () => { - it('from() returns integer', () => { - const value = BigNumber.from('1000000000000000000'); + it('create() returns integer', () => { + const value = BigNumber.create('1000000000000000000'); expect(value.toString()).toEqual('1000000000000000000'); expect(value.toJSON()).toEqual('0x0de0b6b3a7640000'); expect(value.toDecimal(0)).toEqual('1000000000000000000'); @@ -26,12 +26,12 @@ describe('BigNumber', () => { }); it('does not create a new instance if BigNumber instance passed', () => { - const value = BigNumber.from(0x1); - expect(BigNumber.from(value) === value).toBe(true); + const value = BigNumber.create(0x1); + expect(BigNumber.create(value) === value).toBe(true); }); describe('math', () => { - const from = (value: number) => BigNumber.from(value); + const from = (value: number) => BigNumber.create(value); it('add() multiplies correctly', () => { expect(from(2).add(from(3)).toString()).toEqual('5'); @@ -49,9 +49,9 @@ describe('BigNumber', () => { expect(from(15).div(from(5)).toString()).toEqual('3'); }); - it('eq() returns correct value', () => { - expect(from(1).eq(from(1))).toBe(true); - expect(from(1).eq(from(-1))).toBe(false); + it('equals() returns correct value', () => { + expect(from(1).equals(from(1))).toBe(true); + expect(from(1).equals(from(-1))).toBe(false); }); }); }); diff --git a/packages/core/src/dataTypes/BigNumber/BigNumber.ts b/packages/core/src/dataTypes/BigNumber/BigNumber.ts index 1f7b71a04b..9ede5587cd 100644 --- a/packages/core/src/dataTypes/BigNumber/BigNumber.ts +++ b/packages/core/src/dataTypes/BigNumber/BigNumber.ts @@ -4,7 +4,7 @@ import { BigNumberParser, BigNumberPrimitive } from './BigNumberParser'; export type BigNumberish = BigNumber | BigNumberPrimitive; export class BigNumber { - public static from(value: BigNumberish): BigNumber { + public static create(value: BigNumberish): BigNumber { if (value instanceof BigNumber) { return value; } @@ -37,7 +37,7 @@ export class BigNumber { return new BigNumber(this.value / asBigInt(value)); } - public eq(value: BigNumber): boolean { + public equals(value: BigNumber): boolean { return this.value === value.toBigInt(); } @@ -59,5 +59,5 @@ export class BigNumber { } function asBigInt(value: BigNumberish): bigint { - return BigNumber.from(value).toBigInt(); + return BigNumber.create(value).toBigInt(); } diff --git a/packages/evmApi/src/resolvers/account/getTokenTransfers.ts b/packages/evmApi/src/resolvers/account/getTokenTransfers.ts index e4c961fd13..2dd4491122 100644 --- a/packages/evmApi/src/resolvers/account/getTokenTransfers.ts +++ b/packages/evmApi/src/resolvers/account/getTokenTransfers.ts @@ -26,7 +26,7 @@ export const getTokenTransfersResolver = new ApiPaginatedResolver({ address: EvmAddress.create(transfer.address), toAddress: EvmAddress.create(transfer.to_address), fromAddress: EvmAddress.create(transfer.from_address), - value: BigNumber.from(transfer.value), + value: BigNumber.create(transfer.value), blockTimestamp: new Date(transfer.block_timestamp), })), resultToJson: (data) => diff --git a/packages/evmApi/src/resolvers/account/getTransactions.ts b/packages/evmApi/src/resolvers/account/getTransactions.ts index f83ab350ec..e1cb578541 100644 --- a/packages/evmApi/src/resolvers/account/getTransactions.ts +++ b/packages/evmApi/src/resolvers/account/getTransactions.ts @@ -44,7 +44,7 @@ export const getTransactionsResolver = new ApiPaginatedResolver({ blockNumber: +transaction.block_number, blockTimestamp: new Date(transaction.block_timestamp), gasPrice: transaction.gas_price, - gasLimit: BigNumber.from(transaction.gas), + gasLimit: BigNumber.create(transaction.gas), to: transaction.to_address, // Not specified in Api response accessList: undefined, diff --git a/packages/evmApi/src/resolvers/token/getTokenAllowance.ts b/packages/evmApi/src/resolvers/token/getTokenAllowance.ts index ba02736630..d3d5435dac 100644 --- a/packages/evmApi/src/resolvers/token/getTokenAllowance.ts +++ b/packages/evmApi/src/resolvers/token/getTokenAllowance.ts @@ -24,7 +24,7 @@ export const getTokenAllowanceResolver = new ApiResolver({ name: 'getTokenAllowance', getUrl: (params: Params) => `${BASE_URL}/erc20/${params.address}/allowance`, apiToResult: (data: ApiResult) => ({ - allowance: BigNumber.from(data.allowance), + allowance: BigNumber.create(data.allowance), }), resultToJson: (data) => ({ allowance: data.allowance.toString(), diff --git a/packages/evmUtils/src/dataTypes/Erc20Value/Erc20Value.ts b/packages/evmUtils/src/dataTypes/Erc20Value/Erc20Value.ts index 0211f48641..c1364a25e6 100644 --- a/packages/evmUtils/src/dataTypes/Erc20Value/Erc20Value.ts +++ b/packages/evmUtils/src/dataTypes/Erc20Value/Erc20Value.ts @@ -42,7 +42,7 @@ export class Erc20Value implements MoralisData { const erc20ValueA = Erc20Value.create(valueA); const erc20ValueB = Erc20Value.create(valueB); - return erc20ValueA.value.eq(erc20ValueB.value); + return erc20ValueA.value.equals(erc20ValueB.value); } equals(value: Erc20Valueish): boolean { diff --git a/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts b/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts index be830538f3..bb238f6b93 100644 --- a/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts +++ b/packages/evmUtils/src/dataTypes/EvmNative/EvmNative.ts @@ -55,7 +55,7 @@ export class EvmNative implements MoralisData { const evmNativeA = EvmNative.create(valueA); const evmNativeB = EvmNative.create(valueB); - return evmNativeA.rawValue.eq(evmNativeB.rawValue); + return evmNativeA.rawValue.equals(evmNativeB.rawValue); } public equals(value: EvmNative): boolean { diff --git a/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransaction.ts b/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransaction.ts index b42140a5d7..e9151002e0 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransaction.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransaction/EvmTransaction.ts @@ -39,10 +39,10 @@ export class EvmTransaction implements MoralisDataObject { return { to: maybe(value.to, EvmAddress.create), from: maybe(value.from, EvmAddress.create), - nonce: maybe(value.nonce, BigNumber.from), + nonce: maybe(value.nonce, BigNumber.create), - gasLimit: maybe(value.gasLimit, BigNumber.from), - gasPrice: maybe(value.gasPrice, BigNumber.from), + gasLimit: maybe(value.gasLimit, BigNumber.create), + gasPrice: maybe(value.gasPrice, BigNumber.create), data: maybe(value.data), value: maybe(value.value, (val) => EvmNative.create(val, 'wei')), @@ -51,8 +51,8 @@ export class EvmTransaction implements MoralisDataObject { type: maybe(value.type), accessList: maybe(value.accessList, accessListify), - maxPriorityFeePerGas: maybe(value.maxPriorityFeePerGas, BigNumber.from), - maxFeePerGas: maybe(value.maxFeePerGas, BigNumber.from), + maxPriorityFeePerGas: maybe(value.maxPriorityFeePerGas, BigNumber.create), + maxFeePerGas: maybe(value.maxFeePerGas, BigNumber.create), }; } diff --git a/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.test.ts b/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.test.ts index 0f81041a1e..a4863bae30 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.test.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.test.ts @@ -83,7 +83,7 @@ const transactionResponseData: EvmTransactionResponseInput = { hash: HASH, }; -const expectedTotalGas = BigNumber.from(inputWithAllData.cumulativeGasUsed).mul(inputWithAllData.gasPrice).toString(); +const expectedTotalGas = BigNumber.create(inputWithAllData.cumulativeGasUsed).mul(inputWithAllData.gasPrice).toString(); describe('EvmTransactionReceipt', () => { beforeAll(() => { diff --git a/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.ts b/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.ts index 591109b9f5..4c7a05620b 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransactionReceipt/EvmTransactionReceipt.ts @@ -35,9 +35,9 @@ export class EvmTransactionReceipt implements MoralisDataObject { contractAddress: maybe(value.contractAddress, EvmAddress.create), - gasUsed: BigNumber.from(value.gasUsed), - cumulativeGasUsed: BigNumber.from(value.cumulativeGasUsed), - gasPrice: BigNumber.from(value.gasPrice), + gasUsed: BigNumber.create(value.gasUsed), + cumulativeGasUsed: BigNumber.create(value.cumulativeGasUsed), + gasPrice: BigNumber.create(value.gasPrice), logs: value.logs?.map((log) => EvmTransactionLog.create(log)), diff --git a/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponse.ts b/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponse.ts index 73fc711e52..961a0b9b97 100644 --- a/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponse.ts +++ b/packages/evmUtils/src/dataTypes/EvmTransactionResponse/EvmTransactionResponse.ts @@ -42,7 +42,7 @@ export class EvmTransactionResponse implements MoralisDataObject { static parse(value: EvmTransactionResponseInput): EvmTransactionResponseData { return { hash: value.hash, - nonce: BigNumber.from(value.nonce || 0), // TODO: what if nonce is empty? should be zero? + nonce: BigNumber.create(value.nonce || 0), // TODO: what if nonce is empty? should be zero? chain: EvmChain.create(value.chain), from: EvmAddress.create(value.from), @@ -54,15 +54,15 @@ export class EvmTransactionResponse implements MoralisDataObject { blockHash: maybe(value.blockHash), blockTimestamp: maybe(value.blockTimestamp, (value) => (value instanceof Date ? value : new Date(value))), - gasLimit: maybe(value.gasLimit, BigNumber.from), - gasPrice: maybe(value.gasPrice, BigNumber.from), + gasLimit: maybe(value.gasLimit, BigNumber.create), + gasPrice: maybe(value.gasPrice, BigNumber.create), data: maybe(value.data), type: maybe(value.type), - maxPriorityFeePerGas: maybe(value.maxPriorityFeePerGas, BigNumber.from), - maxFeePerGas: maybe(value.maxFeePerGas, BigNumber.from), + maxPriorityFeePerGas: maybe(value.maxPriorityFeePerGas, BigNumber.create), + maxFeePerGas: maybe(value.maxFeePerGas, BigNumber.create), }; } From d032d648935558ff4dee5e15348b6f3a681271c1 Mon Sep 17 00:00:00 2001 From: b4rtaz Date: Wed, 27 Jul 2022 11:52:23 +0200 Subject: [PATCH 7/7] hardening. --- .../BigNumber/BigNumberParser.test.ts | 29 ++++++++++++------- .../dataTypes/BigNumber/BigNumberParser.ts | 18 ++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/packages/core/src/dataTypes/BigNumber/BigNumberParser.test.ts b/packages/core/src/dataTypes/BigNumber/BigNumberParser.test.ts index 8a458caee7..0e05b749d5 100644 --- a/packages/core/src/dataTypes/BigNumber/BigNumberParser.test.ts +++ b/packages/core/src/dataTypes/BigNumber/BigNumberParser.test.ts @@ -23,6 +23,9 @@ describe('BigNumberParser', () => { it('throws an error when NaN passed', () => { expect(() => parseInt(NaN)).toThrowError('The number NaN cannot be converted to a BigInt'); + expect(() => parseInt(null as any)).toThrowError('Value is null'); + expect(() => parseInt(undefined as any)).toThrowError('Value is undefined'); + expect(() => parseInt('')).toThrowError('Value is empty'); }); }); @@ -59,20 +62,26 @@ describe('BigNumberParser', () => { }); it('throws an error when invalid string passed', () => { - function test(input: string, expectedError: string = 'Cannot convert') { + const cannotConvertExpectedError = 'Cannot convert'; + const emptyFragmentsExpectedError = 'Value has empty fragments'; + + function test(input: string, expectedError: string) { expect(() => parseDecimal(input, 0)).toThrowError(expectedError); } - test('lorem ipsum'); - test('-x'); - test('x'); - test('##'); - test('$$'); - test('!'); + test('lorem ipsum', cannotConvertExpectedError); + test('-x', cannotConvertExpectedError); + test('x', cannotConvertExpectedError); + test('##', cannotConvertExpectedError); + test('$$', cannotConvertExpectedError); + test('!', cannotConvertExpectedError); + test('.', emptyFragmentsExpectedError); + test('', emptyFragmentsExpectedError); + test('-', emptyFragmentsExpectedError); + test('', emptyFragmentsExpectedError); test('..', 'Value has more than one dot'); - test('.', 'Value has empty fragments'); - test('', 'Value has empty fragments'); - test('-', 'Value has empty fragments'); + test(null as any, 'Value is null'); + test(undefined as any, 'Value is undefined'); }); it('throws an error when fractional part is wrong', () => { diff --git a/packages/core/src/dataTypes/BigNumber/BigNumberParser.ts b/packages/core/src/dataTypes/BigNumber/BigNumberParser.ts index 026d5b7944..cfa14bf559 100644 --- a/packages/core/src/dataTypes/BigNumber/BigNumberParser.ts +++ b/packages/core/src/dataTypes/BigNumber/BigNumberParser.ts @@ -4,7 +4,13 @@ export type BigNumberPrimitive = number | string | bigint; export class BigNumberParser { public static parseInt(value: BigNumberPrimitive): bigint { + assertNotEmpty(value); + if (typeof value === 'string') { + if (value.length === 0) { + throw createError('Value is empty'); + } + const isNegativeHex = value.startsWith('-0x'); if (isNegativeHex) { value = value.substring(1); @@ -15,10 +21,13 @@ export class BigNumberParser { } return result; } + return BigInt(value); } public static parseDecimal(value: BigNumberPrimitive, decimals: number): bigint { + assertNotEmpty(value); + const multiplier = getMultiplier(decimals); if (typeof value === 'number') { @@ -65,6 +74,15 @@ export class BigNumberParser { } } +function assertNotEmpty(value: BigNumberPrimitive) { + if (value === null) { + throw createError('Value is null'); + } + if (value === undefined) { + throw createError('Value is undefined'); + } +} + function getMultiplier(decimals: number): bigint { if (decimals < 0) { throw createError('Invalid decimals');