Add function assertions required for staking rewards fuzzing: withdrawDelegatorRewards, finalizePool, and endEpoch. Also adds payProtocolFee-related assertions to fillOrder
This commit is contained in:
@@ -102,15 +102,6 @@ contract TestMixinCumulativeRewards is
|
||||
_cumulativeRewardsByPoolLastStored[poolId] = epoch;
|
||||
}
|
||||
|
||||
/// @dev Returns the most recent cumulative reward for a given pool.
|
||||
function getMostRecentCumulativeReward(bytes32 poolId)
|
||||
public
|
||||
returns (IStructs.Fraction memory)
|
||||
{
|
||||
uint256 mostRecentEpoch = _cumulativeRewardsByPoolLastStored[poolId];
|
||||
return _cumulativeRewardsByPool[poolId][mostRecentEpoch];
|
||||
}
|
||||
|
||||
/// @dev Returns the raw cumulative reward for a given pool in an epoch.
|
||||
/// This is considered "raw" because the internal implementation
|
||||
/// (_getCumulativeRewardAtEpochRaw) will query other state variables
|
||||
@@ -122,4 +113,3 @@ contract TestMixinCumulativeRewards is
|
||||
return _cumulativeRewardsByPool[poolId][epoch];
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,9 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibFractions.sol";
|
||||
import "../src/Staking.sol";
|
||||
import "../src/interfaces/IStructs.sol";
|
||||
|
||||
|
||||
contract TestStaking is
|
||||
@@ -56,6 +58,78 @@ contract TestStaking is
|
||||
testZrxVaultAddress = zrxVaultAddress;
|
||||
}
|
||||
|
||||
function getMostRecentCumulativeReward(bytes32 poolId)
|
||||
external
|
||||
view
|
||||
returns (IStructs.Fraction memory cumulativeRewards, uint256 lastStoredEpoch)
|
||||
{
|
||||
lastStoredEpoch = _cumulativeRewardsByPoolLastStored[poolId];
|
||||
cumulativeRewards = _cumulativeRewardsByPool[poolId][lastStoredEpoch];
|
||||
}
|
||||
|
||||
function computeMemberRewardOverInterval(
|
||||
bytes32 poolId,
|
||||
uint256 memberStakeOverInterval,
|
||||
uint256 beginEpoch,
|
||||
uint256 endEpoch
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256 reward)
|
||||
{
|
||||
// Sanity check if we can skip computation, as it will result in zero.
|
||||
if (memberStakeOverInterval == 0 || beginEpoch == endEpoch) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sanity check interval
|
||||
require(beginEpoch < endEpoch, "CR_INTERVAL_INVALID");
|
||||
|
||||
// Sanity check begin reward
|
||||
IStructs.Fraction memory beginReward = getCumulativeRewardAtEpoch(poolId, beginEpoch);
|
||||
IStructs.Fraction memory endReward = getCumulativeRewardAtEpoch(poolId, endEpoch);
|
||||
|
||||
// Compute reward
|
||||
reward = LibFractions.scaleDifference(
|
||||
endReward.numerator,
|
||||
endReward.denominator,
|
||||
beginReward.numerator,
|
||||
beginReward.denominator,
|
||||
memberStakeOverInterval
|
||||
);
|
||||
}
|
||||
|
||||
function getCumulativeRewardAtEpoch(bytes32 poolId, uint256 epoch)
|
||||
public
|
||||
view
|
||||
returns (IStructs.Fraction memory cumulativeReward)
|
||||
{
|
||||
// Return CR at `epoch`, given it's set.
|
||||
cumulativeReward = _cumulativeRewardsByPool[poolId][epoch];
|
||||
if (_isCumulativeRewardSet(cumulativeReward)) {
|
||||
return cumulativeReward;
|
||||
}
|
||||
|
||||
// Return CR at `epoch-1`, given it's set.
|
||||
uint256 lastEpoch = epoch.safeSub(1);
|
||||
cumulativeReward = _cumulativeRewardsByPool[poolId][lastEpoch];
|
||||
if (_isCumulativeRewardSet(cumulativeReward)) {
|
||||
return cumulativeReward;
|
||||
}
|
||||
|
||||
// Return the most recent CR, given it's less than `epoch`.
|
||||
uint256 mostRecentEpoch = _cumulativeRewardsByPoolLastStored[poolId];
|
||||
if (mostRecentEpoch < epoch) {
|
||||
cumulativeReward = _cumulativeRewardsByPool[poolId][mostRecentEpoch];
|
||||
if (_isCumulativeRewardSet(cumulativeReward)) {
|
||||
return cumulativeReward;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise return an empty CR.
|
||||
return IStructs.Fraction(0, 1);
|
||||
}
|
||||
|
||||
/// @dev Overridden to use testWethAddress;
|
||||
function getWethContract()
|
||||
public
|
||||
|
@@ -45,6 +45,7 @@ export { StakingRevertErrors, FixedMathRevertErrors } from '@0x/utils';
|
||||
export { constants } from './constants';
|
||||
export {
|
||||
AggregatedStats,
|
||||
AggregatedStatsByEpoch,
|
||||
StakeInfo,
|
||||
StakeStatus,
|
||||
StoredBalance,
|
||||
@@ -52,6 +53,7 @@ export {
|
||||
OwnerStakeByStatus,
|
||||
GlobalStakeByStatus,
|
||||
StakingPool,
|
||||
PoolStats,
|
||||
} from './types';
|
||||
export {
|
||||
ContractArtifact,
|
||||
|
@@ -147,45 +147,49 @@ export interface OwnerStakeByStatus {
|
||||
};
|
||||
}
|
||||
|
||||
interface Fraction {
|
||||
numerator: BigNumber;
|
||||
denominator: BigNumber;
|
||||
}
|
||||
|
||||
export class StakingPool {
|
||||
public delegatedStake: StoredBalance = new StoredBalance();
|
||||
public rewards: BigNumber = constants.ZERO_AMOUNT;
|
||||
public cumulativeRewards: {
|
||||
[epoch: string]: Fraction;
|
||||
} = {};
|
||||
public cumulativeRewardsLastStored: string = stakingConstants.INITIAL_EPOCH.toString();
|
||||
public stats: {
|
||||
[epoch: string]: PoolStats;
|
||||
} = {};
|
||||
|
||||
constructor(public readonly operator: string, public operatorShare: number) {}
|
||||
|
||||
public finalize(): void {}
|
||||
public creditProtocolFee(): void {}
|
||||
public withdrawDelegatorRewards(delegator: string): void {}
|
||||
public delegateStake(delegator: string, amount: BigNumber): void {}
|
||||
public undelegateStake(delegator: string, amount: BigNumber): void {}
|
||||
export interface StakingPool {
|
||||
operator: string;
|
||||
operatorShare: number;
|
||||
delegatedStake: StoredBalance;
|
||||
lastFinalized: BigNumber; // Epoch during which the pool was most recently finalized
|
||||
}
|
||||
|
||||
export interface StakingPoolById {
|
||||
[poolId: string]: StakingPool;
|
||||
}
|
||||
|
||||
export interface PoolStats {
|
||||
feesCollected: BigNumber;
|
||||
weightedStake: BigNumber;
|
||||
membersStake: BigNumber;
|
||||
export class PoolStats {
|
||||
public feesCollected: BigNumber = constants.ZERO_AMOUNT;
|
||||
public weightedStake: BigNumber = constants.ZERO_AMOUNT;
|
||||
public membersStake: BigNumber = constants.ZERO_AMOUNT;
|
||||
|
||||
public static fromArray(arr: [BigNumber, BigNumber, BigNumber]): PoolStats {
|
||||
const poolStats = new PoolStats();
|
||||
[poolStats.feesCollected, poolStats.weightedStake, poolStats.membersStake] = arr;
|
||||
return poolStats;
|
||||
}
|
||||
}
|
||||
|
||||
export interface AggregatedStats {
|
||||
rewardsAvailable: BigNumber;
|
||||
numPoolsToFinalize: BigNumber;
|
||||
totalFeesCollected: BigNumber;
|
||||
totalWeightedStake: BigNumber;
|
||||
totalRewardsFinalized: BigNumber;
|
||||
export class AggregatedStats {
|
||||
public rewardsAvailable: BigNumber = constants.ZERO_AMOUNT;
|
||||
public numPoolsToFinalize: BigNumber = constants.ZERO_AMOUNT;
|
||||
public totalFeesCollected: BigNumber = constants.ZERO_AMOUNT;
|
||||
public totalWeightedStake: BigNumber = constants.ZERO_AMOUNT;
|
||||
public totalRewardsFinalized: BigNumber = constants.ZERO_AMOUNT;
|
||||
|
||||
public static fromArray(arr: [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber]): AggregatedStats {
|
||||
const aggregatedStats = new AggregatedStats();
|
||||
[
|
||||
aggregatedStats.rewardsAvailable,
|
||||
aggregatedStats.numPoolsToFinalize,
|
||||
aggregatedStats.totalFeesCollected,
|
||||
aggregatedStats.totalWeightedStake,
|
||||
aggregatedStats.totalRewardsFinalized,
|
||||
] = arr;
|
||||
return aggregatedStats;
|
||||
}
|
||||
}
|
||||
|
||||
export interface AggregatedStatsByEpoch {
|
||||
[epoch: string]: AggregatedStats;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { blockchainTests, constants, describe, expect, shortZip } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants, describe, expect, shortZip, toBaseUnitAmount } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, StakingRevertErrors } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -9,7 +9,6 @@ import { FinalizerActor } from './actors/finalizer_actor';
|
||||
import { PoolOperatorActor } from './actors/pool_operator_actor';
|
||||
import { StakerActor } from './actors/staker_actor';
|
||||
import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper';
|
||||
import { toBaseUnitAmount } from './utils/number_utils';
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
// tslint:disable:max-file-line-count
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { blockchainTests, describe } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, describe, toBaseUnitAmount } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, StakingRevertErrors } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -7,7 +7,6 @@ import { StakeInfo, StakeStatus } from '../src/types';
|
||||
|
||||
import { StakerActor } from './actors/staker_actor';
|
||||
import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper';
|
||||
import { toBaseUnitAmount } from './utils/number_utils';
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
blockchainTests.resets('Stake Statuses', env => {
|
||||
|
@@ -1,20 +1,18 @@
|
||||
import {
|
||||
assertIntegerRoughlyEquals as assertRoughlyEquals,
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
Numberish,
|
||||
randomAddress,
|
||||
toBaseUnitAmount,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import { LogEntry } from 'ethereum-types';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import {
|
||||
assertIntegerRoughlyEquals as assertRoughlyEquals,
|
||||
getRandomInteger,
|
||||
toBaseUnitAmount,
|
||||
} from '../utils/number_utils';
|
||||
|
||||
import {
|
||||
TestDelegatorRewardsContract,
|
||||
|
@@ -1,10 +1,13 @@
|
||||
import {
|
||||
assertIntegerRoughlyEquals,
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
Numberish,
|
||||
shortZip,
|
||||
toBaseUnitAmount,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber, hexUtils, StakingRevertErrors } from '@0x/utils';
|
||||
import { LogEntry } from 'ethereum-types';
|
||||
@@ -13,7 +16,6 @@ import * as _ from 'lodash';
|
||||
import { constants as stakingConstants } from '../../src/constants';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { assertIntegerRoughlyEquals, getRandomInteger, toBaseUnitAmount } from '../utils/number_utils';
|
||||
|
||||
import {
|
||||
IStakingEventsEpochEndedEventArgs,
|
||||
|
@@ -1,9 +1,14 @@
|
||||
import { blockchainTests, Numberish } from '@0x/contracts-test-utils';
|
||||
import {
|
||||
assertRoughlyEquals,
|
||||
blockchainTests,
|
||||
getRandomInteger,
|
||||
getRandomPortion,
|
||||
Numberish,
|
||||
toDecimal,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { assertRoughlyEquals, getRandomInteger, getRandomPortion, toDecimal } from '../utils/number_utils';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { TestCobbDouglasContract } from '../wrappers';
|
||||
|
||||
|
@@ -1,10 +1,16 @@
|
||||
import { blockchainTests, expect, Numberish } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, FixedMathRevertErrors, hexUtils } from '@0x/utils';
|
||||
import {
|
||||
assertRoughlyEquals,
|
||||
blockchainTests,
|
||||
expect,
|
||||
fromFixed,
|
||||
Numberish,
|
||||
toDecimal,
|
||||
toFixed,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber, FixedMathRevertErrors } from '@0x/utils';
|
||||
import { Decimal } from 'decimal.js';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { assertRoughlyEquals, fromFixed, toDecimal, toFixed } from '../utils/number_utils';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { TestLibFixedMathContract } from '../wrappers';
|
||||
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import { blockchainTests, expect } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, expect, toBaseUnitAmount } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants as stakingConstants } from '../../src/constants';
|
||||
import { toBaseUnitAmount } from '../utils/number_utils';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { TestMixinCumulativeRewardsContract } from '../wrappers';
|
||||
@@ -74,7 +73,9 @@ blockchainTests.resets('MixinCumulativeRewards unit tests', env => {
|
||||
await testContract
|
||||
.addCumulativeReward(testPoolId, testRewards[0].numerator, testRewards[0].denominator)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const mostRecentCumulativeReward = await testContract.getMostRecentCumulativeReward(testPoolId).callAsync();
|
||||
const [mostRecentCumulativeReward] = await testContract
|
||||
.getMostRecentCumulativeReward(testPoolId)
|
||||
.callAsync();
|
||||
expect(mostRecentCumulativeReward).to.deep.equal(testRewards[0]);
|
||||
});
|
||||
|
||||
@@ -86,7 +87,9 @@ blockchainTests.resets('MixinCumulativeRewards unit tests', env => {
|
||||
await testContract
|
||||
.addCumulativeReward(testPoolId, testRewards[1].numerator, testRewards[1].denominator)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const mostRecentCumulativeReward = await testContract.getMostRecentCumulativeReward(testPoolId).callAsync();
|
||||
const [mostRecentCumulativeReward] = await testContract
|
||||
.getMostRecentCumulativeReward(testPoolId)
|
||||
.callAsync();
|
||||
expect(mostRecentCumulativeReward).to.deep.equal(testRewards[0]);
|
||||
});
|
||||
|
||||
@@ -98,7 +101,9 @@ blockchainTests.resets('MixinCumulativeRewards unit tests', env => {
|
||||
await testContract
|
||||
.addCumulativeReward(testPoolId, testRewards[1].numerator, testRewards[1].denominator)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const mostRecentCumulativeReward = await testContract.getMostRecentCumulativeReward(testPoolId).callAsync();
|
||||
const [mostRecentCumulativeReward] = await testContract
|
||||
.getMostRecentCumulativeReward(testPoolId)
|
||||
.callAsync();
|
||||
expect(mostRecentCumulativeReward).to.deep.equal(sumOfTestRewardsNormalized);
|
||||
});
|
||||
});
|
||||
|
@@ -3,6 +3,7 @@ import {
|
||||
constants,
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
Numberish,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
@@ -19,8 +20,6 @@ import {
|
||||
TestProtocolFeesEvents,
|
||||
} from '../wrappers';
|
||||
|
||||
import { getRandomInteger } from '../utils/number_utils';
|
||||
|
||||
blockchainTests('Protocol Fees unit tests', env => {
|
||||
let ownerAddress: string;
|
||||
let exchangeAddress: string;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainTestsEnvironment, expect, txDefaults } from '@0x/contracts-test-utils';
|
||||
import { BlockchainTestsEnvironment, expect, toBaseUnitAmount, txDefaults } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { DecodedLogEntry, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
@@ -8,7 +8,6 @@ import { artifacts } from '../artifacts';
|
||||
import { TestCumulativeRewardTrackingContract, TestCumulativeRewardTrackingEvents } from '../wrappers';
|
||||
|
||||
import { StakingApiWrapper } from './api_wrapper';
|
||||
import { toBaseUnitAmount } from './number_utils';
|
||||
|
||||
export enum TestAction {
|
||||
Finalize,
|
||||
|
@@ -1,116 +0,0 @@
|
||||
import { expect, Numberish } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as crypto from 'crypto';
|
||||
import { Decimal } from 'decimal.js';
|
||||
|
||||
Decimal.set({ precision: 80 });
|
||||
|
||||
/**
|
||||
* Convert `x` to a `Decimal` type.
|
||||
*/
|
||||
export function toDecimal(x: Numberish): Decimal {
|
||||
if (BigNumber.isBigNumber(x)) {
|
||||
return new Decimal(x.toString(10));
|
||||
}
|
||||
return new Decimal(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random integer between `min` and `max`, inclusive.
|
||||
*/
|
||||
export function getRandomInteger(min: Numberish, max: Numberish): BigNumber {
|
||||
const range = new BigNumber(max).minus(min);
|
||||
return getRandomPortion(range).plus(min);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random integer between `0` and `total`, inclusive.
|
||||
*/
|
||||
export function getRandomPortion(total: Numberish): BigNumber {
|
||||
return new BigNumber(total).times(getRandomFloat(0, 1)).integerValue(BigNumber.ROUND_HALF_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random, high-precision decimal between `min` and `max`, inclusive.
|
||||
*/
|
||||
export function getRandomFloat(min: Numberish, max: Numberish): BigNumber {
|
||||
// Generate a really high precision number between [0, 1]
|
||||
const r = new BigNumber(crypto.randomBytes(32).toString('hex'), 16).dividedBy(new BigNumber(2).pow(256).minus(1));
|
||||
return new BigNumber(max)
|
||||
.minus(min)
|
||||
.times(r)
|
||||
.plus(min);
|
||||
}
|
||||
|
||||
export const FIXED_POINT_BASE = new BigNumber(2).pow(127);
|
||||
|
||||
/**
|
||||
* Convert `n` to fixed-point integer represenatation.
|
||||
*/
|
||||
export function toFixed(n: Numberish): BigNumber {
|
||||
return new BigNumber(n).times(FIXED_POINT_BASE).integerValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert `n` from fixed-point integer represenatation.
|
||||
*/
|
||||
export function fromFixed(n: Numberish): BigNumber {
|
||||
return new BigNumber(n).dividedBy(FIXED_POINT_BASE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts two decimal numbers to integers with `precision` digits, then returns
|
||||
* the absolute difference.
|
||||
*/
|
||||
export function getNumericalDivergence(a: Numberish, b: Numberish, precision: number = 18): number {
|
||||
const _a = new BigNumber(a);
|
||||
const _b = new BigNumber(b);
|
||||
const maxIntegerDigits = Math.max(
|
||||
_a.integerValue(BigNumber.ROUND_DOWN).sd(true),
|
||||
_b.integerValue(BigNumber.ROUND_DOWN).sd(true),
|
||||
);
|
||||
const _toInteger = (n: BigNumber) => {
|
||||
const base = 10 ** (precision - maxIntegerDigits);
|
||||
return n.times(base).integerValue(BigNumber.ROUND_DOWN);
|
||||
};
|
||||
return _toInteger(_a)
|
||||
.minus(_toInteger(_b))
|
||||
.abs()
|
||||
.toNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that two numbers are equal up to `precision` digits.
|
||||
*/
|
||||
export function assertRoughlyEquals(actual: Numberish, expected: Numberish, precision: number = 18): void {
|
||||
if (getNumericalDivergence(actual, expected, precision) <= 1) {
|
||||
return;
|
||||
}
|
||||
expect(actual).to.bignumber.eq(expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that two numbers are equal with up to `maxError` difference between them.
|
||||
*/
|
||||
export function assertIntegerRoughlyEquals(actual: Numberish, expected: Numberish, maxError: number = 1): void {
|
||||
const diff = new BigNumber(actual)
|
||||
.minus(expected)
|
||||
.abs()
|
||||
.toNumber();
|
||||
if (diff <= maxError) {
|
||||
return;
|
||||
}
|
||||
expect(actual).to.bignumber.eq(expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts `amount` into a base unit amount with a specified number of digits. If
|
||||
* no digits are provided, this defaults to 18 digits.
|
||||
*/
|
||||
export function toBaseUnitAmount(amount: Numberish, decimals?: number): BigNumber {
|
||||
const amountAsBigNumber = new BigNumber(amount);
|
||||
const baseDecimals = decimals !== undefined ? decimals : 18;
|
||||
const baseUnitAmount = Web3Wrapper.toBaseUnitAmount(amountAsBigNumber, baseDecimals);
|
||||
return baseUnitAmount;
|
||||
}
|
Reference in New Issue
Block a user