Lowercase public addresses

Normalize the public api addresses to lowercase to prevent an avoidable
error
This commit is contained in:
Jacob Evans 2018-02-06 15:06:56 -08:00
parent 097fc477a2
commit 31f9a848f9
No known key found for this signature in database
GPG Key ID: 2036DA2ADDFB0842
6 changed files with 172 additions and 89 deletions

View File

@ -71,11 +71,12 @@ export class ZeroEx {
* @return Whether the signature is valid for the supplied signerAddress and data. * @return Whether the signature is valid for the supplied signerAddress and data.
*/ */
public static isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean { public static isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
const normalizedSignerAddress = signerAddress.toLowerCase();
assert.isHexString('data', data); assert.isHexString('data', data);
assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema); assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema);
assert.isETHAddressHex('signerAddress', signerAddress); assert.isETHAddressHex('signerAddress', normalizedSignerAddress);
const isValidSignature = signatureUtils.isValidSignature(data, signature, signerAddress); const isValidSignature = signatureUtils.isValidSignature(data, signature, normalizedSignerAddress);
return isValidSignature; return isValidSignature;
} }
/** /**
@ -244,7 +245,9 @@ export class ZeroEx {
shouldAddPersonalMessagePrefix: boolean, shouldAddPersonalMessagePrefix: boolean,
): Promise<ECSignature> { ): Promise<ECSignature> {
assert.isHexString('orderHash', orderHash); assert.isHexString('orderHash', orderHash);
await assert.isSenderAddressAsync('signerAddress', signerAddress, this._web3Wrapper); const normalizedSignerAddress = signerAddress.toLowerCase();
assert.isETHAddressHex('signerAddress', normalizedSignerAddress);
await assert.isSenderAddressAsync('signerAddress', normalizedSignerAddress, this._web3Wrapper);
let msgHashHex = orderHash; let msgHashHex = orderHash;
if (shouldAddPersonalMessagePrefix) { if (shouldAddPersonalMessagePrefix) {
@ -253,7 +256,7 @@ export class ZeroEx {
msgHashHex = ethUtil.bufferToHex(msgHashBuff); msgHashHex = ethUtil.bufferToHex(msgHashBuff);
} }
const signature = await this._web3Wrapper.signTransactionAsync(signerAddress, msgHashHex); const signature = await this._web3Wrapper.signTransactionAsync(normalizedSignerAddress, msgHashHex);
// HACK: There is no consensus on whether the signatureHex string should be formatted as // HACK: There is no consensus on whether the signatureHex string should be formatted as
// v + r + s OR r + s + v, and different clients (even different versions of the same client) // v + r + s OR r + s + v, and different clients (even different versions of the same client)
@ -262,7 +265,7 @@ export class ZeroEx {
const validVParamValues = [27, 28]; const validVParamValues = [27, 28];
const ecSignatureVRS = signatureUtils.parseSignatureHexAsVRS(signature); const ecSignatureVRS = signatureUtils.parseSignatureHexAsVRS(signature);
if (_.includes(validVParamValues, ecSignatureVRS.v)) { if (_.includes(validVParamValues, ecSignatureVRS.v)) {
const isValidVRSSignature = ZeroEx.isValidSignature(orderHash, ecSignatureVRS, signerAddress); const isValidVRSSignature = ZeroEx.isValidSignature(orderHash, ecSignatureVRS, normalizedSignerAddress);
if (isValidVRSSignature) { if (isValidVRSSignature) {
return ecSignatureVRS; return ecSignatureVRS;
} }
@ -270,7 +273,7 @@ export class ZeroEx {
const ecSignatureRSV = signatureUtils.parseSignatureHexAsRSV(signature); const ecSignatureRSV = signatureUtils.parseSignatureHexAsRSV(signature);
if (_.includes(validVParamValues, ecSignatureRSV.v)) { if (_.includes(validVParamValues, ecSignatureRSV.v)) {
const isValidRSVSignature = ZeroEx.isValidSignature(orderHash, ecSignatureRSV, signerAddress); const isValidRSVSignature = ZeroEx.isValidSignature(orderHash, ecSignatureRSV, normalizedSignerAddress);
if (isValidRSVSignature) { if (isValidRSVSignature) {
return ecSignatureRSV; return ecSignatureRSV;
} }

View File

@ -41,15 +41,19 @@ export class EtherTokenWrapper extends ContractWrapper {
depositor: string, depositor: string,
txOpts: TransactionOpts = {}, txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
const normalizedDepositorAddress = depositor.toLowerCase();
const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
assert.isETHAddressHex('depositor', normalizedDepositorAddress);
assert.isETHAddressHex('etherTokenAddress', normalizedEtherTokenAddress);
assert.isValidBaseUnitAmount('amountInWei', amountInWei); assert.isValidBaseUnitAmount('amountInWei', amountInWei);
await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper); await assert.isSenderAddressAsync('depositor', normalizedDepositorAddress, this._web3Wrapper);
const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(depositor); const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(normalizedDepositorAddress);
assert.assert(ethBalanceInWei.gte(amountInWei), ZeroExError.InsufficientEthBalanceForDeposit); assert.assert(ethBalanceInWei.gte(amountInWei), ZeroExError.InsufficientEthBalanceForDeposit);
const wethContract = await this._getEtherTokenContractAsync(etherTokenAddress); const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
const txHash = await wethContract.deposit.sendTransactionAsync({ const txHash = await wethContract.deposit.sendTransactionAsync({
from: depositor, from: normalizedDepositorAddress,
value: amountInWei, value: amountInWei,
gas: txOpts.gasLimit, gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice, gasPrice: txOpts.gasPrice,
@ -71,15 +75,22 @@ export class EtherTokenWrapper extends ContractWrapper {
withdrawer: string, withdrawer: string,
txOpts: TransactionOpts = {}, txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
const normalizedWithdrawerAddress = withdrawer.toLowerCase();
assert.isETHAddressHex('withdrawer', normalizedWithdrawerAddress);
assert.isETHAddressHex('etherTokenAddress', normalizedEtherTokenAddress);
assert.isValidBaseUnitAmount('amountInWei', amountInWei); assert.isValidBaseUnitAmount('amountInWei', amountInWei);
await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper); await assert.isSenderAddressAsync('withdrawer', normalizedWithdrawerAddress, this._web3Wrapper);
const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(etherTokenAddress, withdrawer); const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(
normalizedEtherTokenAddress,
normalizedWithdrawerAddress,
);
assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal); assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal);
const wethContract = await this._getEtherTokenContractAsync(etherTokenAddress); const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, { const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, {
from: withdrawer, from: normalizedWithdrawerAddress,
gas: txOpts.gasLimit, gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice, gasPrice: txOpts.gasPrice,
}); });
@ -100,12 +111,13 @@ export class EtherTokenWrapper extends ContractWrapper {
blockRange: BlockRange, blockRange: BlockRange,
indexFilterValues: IndexedFilterValues, indexFilterValues: IndexedFilterValues,
): Promise<Array<LogWithDecodedArgs<ArgsType>>> { ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
assert.isETHAddressHex('etherTokenAddress', normalizedEtherTokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
const logs = await this._getLogsAsync<ArgsType>( const logs = await this._getLogsAsync<ArgsType>(
etherTokenAddress, normalizedEtherTokenAddress,
eventName, eventName,
blockRange, blockRange,
indexFilterValues, indexFilterValues,
@ -128,12 +140,13 @@ export class EtherTokenWrapper extends ContractWrapper {
indexFilterValues: IndexedFilterValues, indexFilterValues: IndexedFilterValues,
callback: EventCallback<ArgsType>, callback: EventCallback<ArgsType>,
): string { ): string {
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
assert.isETHAddressHex('etherTokenAddress', normalizedEtherTokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback); assert.isFunction('callback', callback);
const subscriptionToken = this._subscribe<ArgsType>( const subscriptionToken = this._subscribe<ArgsType>(
etherTokenAddress, normalizedEtherTokenAddress,
eventName, eventName,
indexFilterValues, indexFilterValues,
artifacts.EtherTokenArtifact.abi, artifacts.EtherTokenArtifact.abi,

View File

@ -179,7 +179,9 @@ export class ExchangeWrapper extends ContractWrapper {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const normalizedTakerAddress = takerAddress.toLowerCase();
assert.isETHAddressHex('takerAddress', normalizedTakerAddress);
await assert.isSenderAddressAsync('takerAddress', normalizedTakerAddress, this._web3Wrapper);
const exchangeInstance = await this._getExchangeContractAsync(); const exchangeInstance = await this._getExchangeContractAsync();
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
@ -192,7 +194,7 @@ export class ExchangeWrapper extends ContractWrapper {
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,
fillTakerTokenAmount, fillTakerTokenAmount,
takerAddress, normalizedTakerAddress,
zrxTokenAddress, zrxTokenAddress,
); );
} }
@ -208,7 +210,7 @@ export class ExchangeWrapper extends ContractWrapper {
signedOrder.ecSignature.r, signedOrder.ecSignature.r,
signedOrder.ecSignature.s, signedOrder.ecSignature.s,
{ {
from: takerAddress, from: normalizedTakerAddress,
gas: orderTransactionOpts.gasLimit, gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice, gasPrice: orderTransactionOpts.gasPrice,
}, },
@ -253,7 +255,9 @@ export class ExchangeWrapper extends ContractWrapper {
); );
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const normalizedTakerAddress = takerAddress.toLowerCase();
assert.isETHAddressHex('takerAddress', normalizedTakerAddress);
await assert.isSenderAddressAsync('takerAddress', normalizedTakerAddress, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
? SHOULD_VALIDATE_BY_DEFAULT ? SHOULD_VALIDATE_BY_DEFAULT
@ -267,7 +271,7 @@ export class ExchangeWrapper extends ContractWrapper {
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,
fillTakerTokenAmount.minus(filledTakerTokenAmount), fillTakerTokenAmount.minus(filledTakerTokenAmount),
takerAddress, normalizedTakerAddress,
zrxTokenAddress, zrxTokenAddress,
); );
filledTakerTokenAmount = filledTakerTokenAmount.plus(singleFilledTakerTokenAmount); filledTakerTokenAmount = filledTakerTokenAmount.plus(singleFilledTakerTokenAmount);
@ -301,7 +305,7 @@ export class ExchangeWrapper extends ContractWrapper {
rArray, rArray,
sArray, sArray,
{ {
from: takerAddress, from: normalizedTakerAddress,
gas: orderTransactionOpts.gasLimit, gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice, gasPrice: orderTransactionOpts.gasPrice,
}, },
@ -344,7 +348,9 @@ export class ExchangeWrapper extends ContractWrapper {
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
); );
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const normalizedTakerAddress = takerAddress.toLowerCase();
assert.isETHAddressHex('takerAddress', normalizedTakerAddress);
await assert.isSenderAddressAsync('takerAddress', normalizedTakerAddress, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
? SHOULD_VALIDATE_BY_DEFAULT ? SHOULD_VALIDATE_BY_DEFAULT
: orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
@ -356,7 +362,7 @@ export class ExchangeWrapper extends ContractWrapper {
exchangeTradeEmulator, exchangeTradeEmulator,
orderFillRequest.signedOrder, orderFillRequest.signedOrder,
orderFillRequest.takerTokenFillAmount, orderFillRequest.takerTokenFillAmount,
takerAddress, normalizedTakerAddress,
zrxTokenAddress, zrxTokenAddress,
); );
} }
@ -389,7 +395,7 @@ export class ExchangeWrapper extends ContractWrapper {
rArray, rArray,
sArray, sArray,
{ {
from: takerAddress, from: normalizedTakerAddress,
gas: orderTransactionOpts.gasLimit, gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice, gasPrice: orderTransactionOpts.gasPrice,
}, },
@ -416,7 +422,9 @@ export class ExchangeWrapper extends ContractWrapper {
): Promise<string> { ): Promise<string> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const normalizedTakerAddress = takerAddress.toLowerCase();
assert.isETHAddressHex('takerAddress', normalizedTakerAddress);
await assert.isSenderAddressAsync('takerAddress', normalizedTakerAddress, this._web3Wrapper);
const exchangeInstance = await this._getExchangeContractAsync(); const exchangeInstance = await this._getExchangeContractAsync();
@ -430,7 +438,7 @@ export class ExchangeWrapper extends ContractWrapper {
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,
fillTakerTokenAmount, fillTakerTokenAmount,
takerAddress, normalizedTakerAddress,
zrxTokenAddress, zrxTokenAddress,
); );
} }
@ -444,7 +452,7 @@ export class ExchangeWrapper extends ContractWrapper {
signedOrder.ecSignature.r, signedOrder.ecSignature.r,
signedOrder.ecSignature.s, signedOrder.ecSignature.s,
{ {
from: takerAddress, from: normalizedTakerAddress,
gas: orderTransactionOpts.gasLimit, gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice, gasPrice: orderTransactionOpts.gasPrice,
}, },
@ -475,7 +483,9 @@ export class ExchangeWrapper extends ContractWrapper {
exchangeContractAddresses, exchangeContractAddresses,
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
); );
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const normalizedTakerAddress = takerAddress.toLowerCase();
assert.isETHAddressHex('takerAddress', normalizedTakerAddress);
await assert.isSenderAddressAsync('takerAddress', normalizedTakerAddress, this._web3Wrapper);
if (_.isEmpty(orderFillRequests)) { if (_.isEmpty(orderFillRequests)) {
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
} }
@ -492,7 +502,7 @@ export class ExchangeWrapper extends ContractWrapper {
exchangeTradeEmulator, exchangeTradeEmulator,
orderFillRequest.signedOrder, orderFillRequest.signedOrder,
orderFillRequest.takerTokenFillAmount, orderFillRequest.takerTokenFillAmount,
takerAddress, normalizedTakerAddress,
zrxTokenAddress, zrxTokenAddress,
); );
} }
@ -520,7 +530,7 @@ export class ExchangeWrapper extends ContractWrapper {
rParams, rParams,
sParams, sParams,
{ {
from: takerAddress, from: normalizedTakerAddress,
gas: orderTransactionOpts.gasLimit, gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice, gasPrice: orderTransactionOpts.gasPrice,
}, },
@ -756,14 +766,16 @@ export class ExchangeWrapper extends ContractWrapper {
): Promise<void> { ): Promise<void> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const normalizedTakerAddress = takerAddress.toLowerCase();
assert.isETHAddressHex('takerAddress', normalizedTakerAddress);
await assert.isSenderAddressAsync('takerAddress', normalizedTakerAddress, this._web3Wrapper);
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,
fillTakerTokenAmount, fillTakerTokenAmount,
takerAddress, normalizedTakerAddress,
zrxTokenAddress, zrxTokenAddress,
); );
} }
@ -802,14 +814,16 @@ export class ExchangeWrapper extends ContractWrapper {
): Promise<void> { ): Promise<void> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const normalizedTakerAddress = takerAddress.toLowerCase();
assert.isETHAddressHex('takerAddress', normalizedTakerAddress);
await assert.isSenderAddressAsync('takerAddress', normalizedTakerAddress, this._web3Wrapper);
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,
fillTakerTokenAmount, fillTakerTokenAmount,
takerAddress, normalizedTakerAddress,
zrxTokenAddress, zrxTokenAddress,
); );
} }

View File

@ -57,10 +57,11 @@ export class TokenRegistryWrapper extends ContractWrapper {
* @return An object that conforms to the Token interface or undefined if token not found. * @return An object that conforms to the Token interface or undefined if token not found.
*/ */
public async getTokenIfExistsAsync(address: string): Promise<Token | undefined> { public async getTokenIfExistsAsync(address: string): Promise<Token | undefined> {
assert.isETHAddressHex('address', address); const normalizedAddress = address.toLowerCase();
assert.isETHAddressHex('address', normalizedAddress);
const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const tokenRegistryContract = await this._getTokenRegistryContractAsync();
const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(address); const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(normalizedAddress);
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata); const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
return token; return token;
} }

View File

@ -2,6 +2,7 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { artifacts } from '../artifacts'; import { artifacts } from '../artifacts';
import { assert } from '../utils/assert';
import { ContractWrapper } from './contract_wrapper'; import { ContractWrapper } from './contract_wrapper';
import { TokenTransferProxyContract } from './generated/token_transfer_proxy'; import { TokenTransferProxyContract } from './generated/token_transfer_proxy';
@ -22,8 +23,12 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
* @return Whether the exchangeContractAddress is authorized. * @return Whether the exchangeContractAddress is authorized.
*/ */
public async isAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> { public async isAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> {
const normalizedExchangeContractAddress = exchangeContractAddress.toLowerCase();
assert.isETHAddressHex('exchangeContractAddress', normalizedExchangeContractAddress);
const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync(); const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync();
const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync(exchangeContractAddress); const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync(
normalizedExchangeContractAddress,
);
return isAuthorized; return isAuthorized;
} }
/** /**

View File

@ -44,12 +44,14 @@ export class TokenWrapper extends ContractWrapper {
ownerAddress: string, ownerAddress: string,
methodOpts?: MethodOpts, methodOpts?: MethodOpts,
): Promise<BigNumber> { ): Promise<BigNumber> {
assert.isETHAddressHex('ownerAddress', ownerAddress); const normalizedTokenAddress = tokenAddress.toLowerCase();
assert.isETHAddressHex('tokenAddress', tokenAddress); const normalizedOwnerAddress = ownerAddress.toLowerCase();
assert.isETHAddressHex('ownerAddress', normalizedOwnerAddress);
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
const tokenContract = await this._getTokenContractAsync(tokenAddress); const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let balance = await tokenContract.balanceOf.callAsync(ownerAddress, defaultBlock); let balance = await tokenContract.balanceOf.callAsync(normalizedOwnerAddress, defaultBlock);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
balance = new BigNumber(balance); balance = new BigNumber(balance);
return balance; return balance;
@ -72,14 +74,17 @@ export class TokenWrapper extends ContractWrapper {
amountInBaseUnits: BigNumber, amountInBaseUnits: BigNumber,
txOpts: TransactionOpts = {}, txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper); const normalizedTokenAddress = tokenAddress.toLowerCase();
assert.isETHAddressHex('spenderAddress', spenderAddress); const normalizedOwnerAddress = ownerAddress.toLowerCase();
assert.isETHAddressHex('tokenAddress', tokenAddress); const normalizedSpenderAddress = spenderAddress.toLowerCase();
await assert.isSenderAddressAsync('ownerAddress', normalizedOwnerAddress, this._web3Wrapper);
assert.isETHAddressHex('spenderAddress', normalizedSpenderAddress);
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
const tokenContract = await this._getTokenContractAsync(tokenAddress); const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
const txHash = await tokenContract.approve.sendTransactionAsync(spenderAddress, amountInBaseUnits, { const txHash = await tokenContract.approve.sendTransactionAsync(normalizedSpenderAddress, amountInBaseUnits, {
from: ownerAddress, from: normalizedOwnerAddress,
gas: txOpts.gasLimit, gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice, gasPrice: txOpts.gasPrice,
}); });
@ -103,10 +108,16 @@ export class TokenWrapper extends ContractWrapper {
spenderAddress: string, spenderAddress: string,
txOpts: TransactionOpts = {}, txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
const normalizedTokenAddress = tokenAddress.toLowerCase();
const normalizedOwnerAddress = ownerAddress.toLowerCase();
const normalizedSpenderAddress = spenderAddress.toLowerCase();
assert.isETHAddressHex('ownerAddress', normalizedOwnerAddress);
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
assert.isETHAddressHex('spenderAddress', normalizedSpenderAddress);
const txHash = await this.setAllowanceAsync( const txHash = await this.setAllowanceAsync(
tokenAddress, normalizedTokenAddress,
ownerAddress, normalizedOwnerAddress,
spenderAddress, normalizedSpenderAddress,
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
txOpts, txOpts,
); );
@ -126,12 +137,19 @@ export class TokenWrapper extends ContractWrapper {
spenderAddress: string, spenderAddress: string,
methodOpts?: MethodOpts, methodOpts?: MethodOpts,
): Promise<BigNumber> { ): Promise<BigNumber> {
assert.isETHAddressHex('ownerAddress', ownerAddress); const normalizedTokenAddress = tokenAddress.toLowerCase();
assert.isETHAddressHex('tokenAddress', tokenAddress); const normalizedOwnerAddress = ownerAddress.toLowerCase();
const normalizedSpenderAddress = spenderAddress.toLowerCase();
assert.isETHAddressHex('ownerAddress', normalizedOwnerAddress);
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
const tokenContract = await this._getTokenContractAsync(tokenAddress); const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let allowanceInBaseUnits = await tokenContract.allowance.callAsync(ownerAddress, spenderAddress, defaultBlock); let allowanceInBaseUnits = await tokenContract.allowance.callAsync(
normalizedOwnerAddress,
normalizedSpenderAddress,
defaultBlock,
);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
allowanceInBaseUnits = new BigNumber(allowanceInBaseUnits); allowanceInBaseUnits = new BigNumber(allowanceInBaseUnits);
return allowanceInBaseUnits; return allowanceInBaseUnits;
@ -147,11 +165,18 @@ export class TokenWrapper extends ContractWrapper {
ownerAddress: string, ownerAddress: string,
methodOpts?: MethodOpts, methodOpts?: MethodOpts,
): Promise<BigNumber> { ): Promise<BigNumber> {
assert.isETHAddressHex('ownerAddress', ownerAddress); const normalizedTokenAddress = tokenAddress.toLowerCase();
assert.isETHAddressHex('tokenAddress', tokenAddress); const normalizedOwnerAddress = ownerAddress.toLowerCase();
assert.isETHAddressHex('ownerAddress', normalizedOwnerAddress);
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress(); const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
const allowanceInBaseUnits = await this.getAllowanceAsync(tokenAddress, ownerAddress, proxyAddress, methodOpts); const allowanceInBaseUnits = await this.getAllowanceAsync(
normalizedTokenAddress,
normalizedOwnerAddress,
proxyAddress,
methodOpts,
);
return allowanceInBaseUnits; return allowanceInBaseUnits;
} }
/** /**
@ -170,14 +195,16 @@ export class TokenWrapper extends ContractWrapper {
amountInBaseUnits: BigNumber, amountInBaseUnits: BigNumber,
txOpts: TransactionOpts = {}, txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
assert.isETHAddressHex('ownerAddress', ownerAddress); const normalizedTokenAddress = tokenAddress.toLowerCase();
assert.isETHAddressHex('tokenAddress', tokenAddress); const normalizedOwnerAddress = ownerAddress.toLowerCase();
assert.isETHAddressHex('ownerAddress', normalizedOwnerAddress);
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress(); const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
const txHash = await this.setAllowanceAsync( const txHash = await this.setAllowanceAsync(
tokenAddress, normalizedTokenAddress,
ownerAddress, normalizedOwnerAddress,
proxyAddress, proxyAddress,
amountInBaseUnits, amountInBaseUnits,
txOpts, txOpts,
@ -200,9 +227,13 @@ export class TokenWrapper extends ContractWrapper {
ownerAddress: string, ownerAddress: string,
txOpts: TransactionOpts = {}, txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
const normalizedTokenAddress = tokenAddress.toLowerCase();
const normalizedOwnerAddress = ownerAddress.toLowerCase();
assert.isETHAddressHex('ownerAddress', normalizedOwnerAddress);
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
const txHash = await this.setProxyAllowanceAsync( const txHash = await this.setProxyAllowanceAsync(
tokenAddress, normalizedTokenAddress,
ownerAddress, normalizedOwnerAddress,
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
txOpts, txOpts,
); );
@ -224,20 +255,24 @@ export class TokenWrapper extends ContractWrapper {
amountInBaseUnits: BigNumber, amountInBaseUnits: BigNumber,
txOpts: TransactionOpts = {}, txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
assert.isETHAddressHex('tokenAddress', tokenAddress); const normalizedTokenAddress = tokenAddress.toLowerCase();
await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper); const normalizedFromAddress = fromAddress.toLowerCase();
const normalizedToAddress = toAddress.toLowerCase();
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
assert.isETHAddressHex('toAddress', toAddress); assert.isETHAddressHex('toAddress', toAddress);
assert.isETHAddressHex('fromAddress', normalizedFromAddress);
await assert.isSenderAddressAsync('fromAddress', normalizedFromAddress, this._web3Wrapper);
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
const tokenContract = await this._getTokenContractAsync(tokenAddress); const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
const fromAddressBalance = await this.getBalanceAsync(tokenAddress, fromAddress); const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress);
if (fromAddressBalance.lessThan(amountInBaseUnits)) { if (fromAddressBalance.lessThan(amountInBaseUnits)) {
throw new Error(ZeroExError.InsufficientBalanceForTransfer); throw new Error(ZeroExError.InsufficientBalanceForTransfer);
} }
const txHash = await tokenContract.transfer.sendTransactionAsync(toAddress, amountInBaseUnits, { const txHash = await tokenContract.transfer.sendTransactionAsync(normalizedToAddress, amountInBaseUnits, {
from: fromAddress, from: normalizedFromAddress,
gas: txOpts.gasLimit, gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice, gasPrice: txOpts.gasPrice,
}); });
@ -265,30 +300,39 @@ export class TokenWrapper extends ContractWrapper {
amountInBaseUnits: BigNumber, amountInBaseUnits: BigNumber,
txOpts: TransactionOpts = {}, txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
assert.isETHAddressHex('tokenAddress', tokenAddress); const normalizedToAddress = toAddress.toLowerCase();
assert.isETHAddressHex('fromAddress', fromAddress); const normalizedFromAddress = fromAddress.toLowerCase();
assert.isETHAddressHex('toAddress', toAddress); const normalizedTokenAddress = tokenAddress.toLowerCase();
await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); const normalizedSenderAddress = senderAddress.toLowerCase();
assert.isETHAddressHex('toAddress', normalizedToAddress);
assert.isETHAddressHex('fromAddress', normalizedFromAddress);
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
assert.isETHAddressHex('senderAddress', normalizedSenderAddress);
await assert.isSenderAddressAsync('senderAddress', normalizedSenderAddress, this._web3Wrapper);
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
const tokenContract = await this._getTokenContractAsync(tokenAddress); const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
const fromAddressAllowance = await this.getAllowanceAsync(tokenAddress, fromAddress, senderAddress); const fromAddressAllowance = await this.getAllowanceAsync(
normalizedTokenAddress,
normalizedFromAddress,
normalizedSenderAddress,
);
if (fromAddressAllowance.lessThan(amountInBaseUnits)) { if (fromAddressAllowance.lessThan(amountInBaseUnits)) {
throw new Error(ZeroExError.InsufficientAllowanceForTransfer); throw new Error(ZeroExError.InsufficientAllowanceForTransfer);
} }
const fromAddressBalance = await this.getBalanceAsync(tokenAddress, fromAddress); const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress);
if (fromAddressBalance.lessThan(amountInBaseUnits)) { if (fromAddressBalance.lessThan(amountInBaseUnits)) {
throw new Error(ZeroExError.InsufficientBalanceForTransfer); throw new Error(ZeroExError.InsufficientBalanceForTransfer);
} }
const txHash = await tokenContract.transferFrom.sendTransactionAsync( const txHash = await tokenContract.transferFrom.sendTransactionAsync(
fromAddress, normalizedFromAddress,
toAddress, normalizedToAddress,
amountInBaseUnits, amountInBaseUnits,
{ {
from: senderAddress, from: normalizedSenderAddress,
gas: txOpts.gasLimit, gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice, gasPrice: txOpts.gasPrice,
}, },
@ -310,12 +354,13 @@ export class TokenWrapper extends ContractWrapper {
indexFilterValues: IndexedFilterValues, indexFilterValues: IndexedFilterValues,
callback: EventCallback<ArgsType>, callback: EventCallback<ArgsType>,
): string { ): string {
assert.isETHAddressHex('tokenAddress', tokenAddress); const normalizedTokenAddress = tokenAddress.toLowerCase();
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents); assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback); assert.isFunction('callback', callback);
const subscriptionToken = this._subscribe<ArgsType>( const subscriptionToken = this._subscribe<ArgsType>(
tokenAddress, normalizedTokenAddress,
eventName, eventName,
indexFilterValues, indexFilterValues,
artifacts.TokenArtifact.abi, artifacts.TokenArtifact.abi,
@ -351,12 +396,13 @@ export class TokenWrapper extends ContractWrapper {
blockRange: BlockRange, blockRange: BlockRange,
indexFilterValues: IndexedFilterValues, indexFilterValues: IndexedFilterValues,
): Promise<Array<LogWithDecodedArgs<ArgsType>>> { ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
assert.isETHAddressHex('tokenAddress', tokenAddress); const normalizedTokenAddress = tokenAddress.toLowerCase();
assert.isETHAddressHex('tokenAddress', normalizedTokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents); assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
const logs = await this._getLogsAsync<ArgsType>( const logs = await this._getLogsAsync<ArgsType>(
tokenAddress, normalizedTokenAddress,
eventName, eventName,
blockRange, blockRange,
indexFilterValues, indexFilterValues,
@ -369,17 +415,18 @@ export class TokenWrapper extends ContractWrapper {
this._tokenContractsByAddress = {}; this._tokenContractsByAddress = {};
} }
private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> { private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> {
let tokenContract = this._tokenContractsByAddress[tokenAddress]; const normalizedTokenAddress = tokenAddress.toLowerCase();
let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress];
if (!_.isUndefined(tokenContract)) { if (!_.isUndefined(tokenContract)) {
return tokenContract; return tokenContract;
} }
const web3ContractInstance = await this._instantiateContractIfExistsAsync( const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.TokenArtifact, artifacts.TokenArtifact,
tokenAddress, normalizedTokenAddress,
); );
const contractInstance = new TokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); const contractInstance = new TokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
tokenContract = contractInstance; tokenContract = contractInstance;
this._tokenContractsByAddress[tokenAddress] = tokenContract; this._tokenContractsByAddress[normalizedTokenAddress] = tokenContract;
return tokenContract; return tokenContract;
} }
} }