diff options
Diffstat (limited to 'packages/utils/src/abi_encoder/evm_data_types/number.ts')
-rw-r--r-- | packages/utils/src/abi_encoder/evm_data_types/number.ts | 71 |
1 files changed, 6 insertions, 65 deletions
diff --git a/packages/utils/src/abi_encoder/evm_data_types/number.ts b/packages/utils/src/abi_encoder/evm_data_types/number.ts index 86acdce07..053a574e3 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/number.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/number.ts @@ -1,11 +1,11 @@ import { DataItem } from 'ethereum-types'; -import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; import { BigNumber } from '../../configured_bignumber'; import { DataTypeFactory, PayloadDataType } from '../abstract_data_types'; import { RawCalldata } from '../calldata'; import * as Constants from '../utils/constants'; +import * as EncoderMath from '../utils/math'; export abstract class Number extends PayloadDataType { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true; @@ -25,73 +25,14 @@ export abstract class Number extends PayloadDataType { : (this._width = Number._DEFAULT_WIDTH); } - public encodeValue(value_: BigNumber | string | number): Buffer { - const value = new BigNumber(value_, 10); - if (value.greaterThan(this.getMaxValue())) { - throw new Error(`Tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`); - } else if (value.lessThan(this.getMinValue())) { - throw new Error(`Tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`); - } - - let valueBuf: Buffer; - if (value.greaterThanOrEqualTo(0)) { - valueBuf = ethUtil.setLengthLeft( - ethUtil.toBuffer(`0x${value.toString(Constants.HEX_BASE)}`), - Constants.EVM_WORD_WIDTH_IN_BYTES, - ); - } else { - // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves. - // Step 1/3: Convert value to positive binary string - const binBase = 2; - const valueBin = value.times(-1).toString(binBase); - - // Step 2/3: Invert binary value - let invertedValueBin = '1'.repeat(Constants.EVM_WORD_WIDTH_IN_BITS - valueBin.length); - _.each(valueBin, (bit: string) => { - invertedValueBin += bit === '1' ? '0' : '1'; - }); - const invertedValue = new BigNumber(invertedValueBin, binBase); - - // Step 3/3: Add 1 to inverted value - // The result is the two's-complement represent of the input value. - const negativeValue = invertedValue.plus(1); - - // Convert the negated value to a hex string - valueBuf = ethUtil.setLengthLeft( - ethUtil.toBuffer(`0x${negativeValue.toString(Constants.HEX_BASE)}`), - Constants.EVM_WORD_WIDTH_IN_BYTES, - ); - } - - return valueBuf; + public encodeValue(value: BigNumber | string | number): Buffer { + const encodedValue = EncoderMath.safeEncodeNumericValue(value, this.getMinValue(), this.getMaxValue()); + return encodedValue; } public decodeValue(calldata: RawCalldata): BigNumber { - const paddedValueBuf = calldata.popWord(); - const paddedValueHex = ethUtil.bufferToHex(paddedValueBuf); - let value = new BigNumber(paddedValueHex, 16); - if (this.getMinValue().lessThan(0)) { - // Check if we're negative - const valueBin = value.toString(Constants.BIN_BASE); - if (valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && valueBin[0].startsWith('1')) { - // Negative - // Step 1/3: Invert binary value - let invertedValueBin = ''; - _.each(valueBin, (bit: string) => { - invertedValueBin += bit === '1' ? '0' : '1'; - }); - const invertedValue = new BigNumber(invertedValueBin, Constants.BIN_BASE); - - // Step 2/3: Add 1 to inverted value - // The result is the two's-complement represent of the input value. - const positiveValue = invertedValue.plus(1); - - // Step 3/3: Invert positive value - const negativeValue = positiveValue.times(-1); - value = negativeValue; - } - } - + const valueBuf = calldata.popWord(); + const value = EncoderMath.safeDecodeNumericValue(valueBuf, this.getMinValue(), this.getMaxValue()); return value; } |