Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Commit

Permalink
Minimize unnecessary type assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
abandeali1 committed Jan 4, 2019
1 parent acf92b5 commit d71196d
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 366 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// tslint:disable:no-unnecessary-type-assertion
import { AbstractBalanceAndProxyAllowanceFetcher, assetDataUtils } from '@0x/order-utils';
import { AssetProxyId, ERC20AssetData, ERC721AssetData, MultiAssetData } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { BlockParamLiteral } from 'ethereum-types';
import * as _ from 'lodash';
Expand All @@ -20,99 +18,73 @@ export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndP
public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
let balance: BigNumber | undefined;
switch (decodedAssetData.assetProxyId) {
case AssetProxyId.ERC20:
const decodedERC20AssetData = decodedAssetData as ERC20AssetData;
balance = await this._erc20Token.getBalanceAsync(decodedERC20AssetData.tokenAddress, userAddress, {
if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
balance = await this._erc20Token.getBalanceAsync(decodedAssetData.tokenAddress, userAddress, {
defaultBlock: this._stateLayer,
});
} else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
const tokenOwner = await this._erc721Token.getOwnerOfAsync(
decodedAssetData.tokenAddress,
decodedAssetData.tokenId,
{
defaultBlock: this._stateLayer,
});
break;
case AssetProxyId.ERC721:
const decodedERC721AssetData = decodedAssetData as ERC721AssetData;
const tokenOwner = await this._erc721Token.getOwnerOfAsync(
decodedERC721AssetData.tokenAddress,
decodedERC721AssetData.tokenId,
{
defaultBlock: this._stateLayer,
},
);
balance = tokenOwner === userAddress ? new BigNumber(1) : new BigNumber(0);
break;
case AssetProxyId.MultiAsset:
// The `balance` for MultiAssetData is the total units of the entire `assetData` that are held by the `userAddress`.
for (const [
index,
},
);
balance = tokenOwner === userAddress ? new BigNumber(1) : new BigNumber(0);
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
// The `balance` for MultiAssetData is the total units of the entire `assetData` that are held by the `userAddress`.
for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
const nestedAmountElement = decodedAssetData.amounts[index];
const nestedAssetBalance = (await this.getBalanceAsync(
nestedAssetDataElement,
] of (decodedAssetData as MultiAssetData).nestedAssetData.entries()) {
const nestedAmountElement = (decodedAssetData as MultiAssetData).amounts[index];
const nestedAssetBalance = (await this.getBalanceAsync(
nestedAssetDataElement,
userAddress,
)).dividedToIntegerBy(nestedAmountElement);
if (_.isUndefined(balance) || nestedAssetBalance.lessThan(balance)) {
balance = nestedAssetBalance;
}
userAddress,
)).dividedToIntegerBy(nestedAmountElement);
if (_.isUndefined(balance) || nestedAssetBalance.lessThan(balance)) {
balance = nestedAssetBalance;
}
break;
default:
throw new Error(`Proxy with id ${decodedAssetData.assetProxyId} not supported`);
}
}
return balance as BigNumber;
}
public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
let proxyAllowance: BigNumber | undefined;
switch (decodedAssetData.assetProxyId) {
case AssetProxyId.ERC20:
const decodedERC20AssetData = decodedAssetData as ERC20AssetData;
proxyAllowance = await this._erc20Token.getProxyAllowanceAsync(
decodedERC20AssetData.tokenAddress,
userAddress,
{
defaultBlock: this._stateLayer,
},
);
break;
case AssetProxyId.ERC721:
const decodedERC721AssetData = decodedAssetData as ERC721AssetData;
const isApprovedForAll = await this._erc721Token.isProxyApprovedForAllAsync(
decodedERC721AssetData.tokenAddress,
userAddress,
if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
proxyAllowance = await this._erc20Token.getProxyAllowanceAsync(decodedAssetData.tokenAddress, userAddress, {
defaultBlock: this._stateLayer,
});
} else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
const isApprovedForAll = await this._erc721Token.isProxyApprovedForAllAsync(
decodedAssetData.tokenAddress,
userAddress,
{
defaultBlock: this._stateLayer,
},
);
if (isApprovedForAll) {
return new BigNumber(this._erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
} else {
const isApproved = await this._erc721Token.isProxyApprovedAsync(
decodedAssetData.tokenAddress,
decodedAssetData.tokenId,
{
defaultBlock: this._stateLayer,
},
);
if (isApprovedForAll) {
return new BigNumber(this._erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
} else {
const isApproved = await this._erc721Token.isProxyApprovedAsync(
decodedERC721AssetData.tokenAddress,
decodedERC721AssetData.tokenId,
{
defaultBlock: this._stateLayer,
},
);
proxyAllowance = isApproved ? new BigNumber(1) : new BigNumber(0);
}
break;
case AssetProxyId.MultiAsset:
// The `proxyAllowance` for MultiAssetData is the total units of the entire `assetData` that the proxies have been approved to spend by the `userAddress`.
for (const [
index,
proxyAllowance = isApproved ? new BigNumber(1) : new BigNumber(0);
}
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
// The `proxyAllowance` for MultiAssetData is the total units of the entire `assetData` that the proxies have been approved to spend by the `userAddress`.
for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
const nestedAmountElement = decodedAssetData.amounts[index];
const nestedAssetAllowance = (await this.getProxyAllowanceAsync(
nestedAssetDataElement,
] of (decodedAssetData as MultiAssetData).nestedAssetData.entries()) {
const nestedAmountElement = (decodedAssetData as MultiAssetData).amounts[index];
const nestedAssetAllowance = (await this.getProxyAllowanceAsync(
nestedAssetDataElement,
userAddress,
)).dividedToIntegerBy(nestedAmountElement);
if (_.isUndefined(proxyAllowance) || nestedAssetAllowance.lessThan(proxyAllowance)) {
proxyAllowance = nestedAssetAllowance;
}
userAddress,
)).dividedToIntegerBy(nestedAmountElement);
if (_.isUndefined(proxyAllowance) || nestedAssetAllowance.lessThan(proxyAllowance)) {
proxyAllowance = nestedAssetAllowance;
}
break;
default:
throw new Error(`Proxy with id ${decodedAssetData.assetProxyId} not supported`);
}
}
return proxyAllowance as BigNumber;
}
Expand Down
59 changes: 17 additions & 42 deletions packages/fill-scenarios/src/fill_scenarios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,7 @@ import { DummyERC20TokenContract, DummyERC721TokenContract, ExchangeContract } f
import * as artifacts from '@0x/contract-artifacts';
import { assetDataUtils } from '@0x/order-utils';
import { orderFactory } from '@0x/order-utils/lib/src/order_factory';
import {
AssetProxyId,
ERC20AssetData,
ERC721AssetData,
MultiAssetData,
OrderWithoutExchangeAddress,
SignedOrder,
} from '@0x/types';
import { OrderWithoutExchangeAddress, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider } from 'ethereum-types';
Expand Down Expand Up @@ -280,42 +273,24 @@ export class FillScenarios {
amount: BigNumber,
): Promise<void> {
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
switch (decodedAssetData.assetProxyId) {
case AssetProxyId.ERC20:
await this._increaseERC20BalanceAndAllowanceAsync(
// tslint:disable-next-line:no-unnecessary-type-assertion
(decodedAssetData as ERC20AssetData).tokenAddress,
userAddress,
amount,
);
break;
case AssetProxyId.ERC721:
await this._increaseERC721BalanceAndAllowanceAsync(
// tslint:disable-next-line:no-unnecessary-type-assertion
(decodedAssetData as ERC721AssetData).tokenAddress,
if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
await this._increaseERC20BalanceAndAllowanceAsync(decodedAssetData.tokenAddress, userAddress, amount);
} else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
await this._increaseERC721BalanceAndAllowanceAsync(
decodedAssetData.tokenAddress,
userAddress,
decodedAssetData.tokenId,
);
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
const amountsElement = decodedAssetData.amounts[index];
const totalAmount = amount.times(amountsElement);
await this._increaseBalanceAndAllowanceWithAssetDataAsync(
nestedAssetDataElement,
userAddress,
// tslint:disable-next-line:no-unnecessary-type-assertion
(decodedAssetData as ERC721AssetData).tokenId,
totalAmount,
);
break;
case AssetProxyId.MultiAsset:
for (const [
index,
nestedAssetDataElement,
// tslint:disable-next-line:no-unnecessary-type-assertion
] of (decodedAssetData as MultiAssetData).nestedAssetData.entries()) {
// tslint:disable-next-line:no-unnecessary-type-assertion
const amountsElement = (decodedAssetData as MultiAssetData).amounts[index];
const totalAmount = amount.times(amountsElement);
await this._increaseBalanceAndAllowanceWithAssetDataAsync(
nestedAssetDataElement,
userAddress,
totalAmount,
);
}
break;
default:
throw new Error(`Proxy with id ${decodedAssetData.assetProxyId} not supported`);
}
}
}
}
36 changes: 28 additions & 8 deletions packages/order-utils/src/asset_data_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
SingleAssetData,
} from '@0x/types';
import { AbiEncoder, BigNumber } from '@0x/utils';
import { MethodAbi } from 'ethereum-types';
import * as _ from 'lodash';

import { constants } from './constants';
Expand All @@ -23,7 +22,7 @@ export const assetDataUtils = {
* @return The hex encoded assetData string
*/
encodeERC20AssetData(tokenAddress: string): string {
const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI as MethodAbi);
const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI);
const args = [tokenAddress];
const assetData = abiEncoder.encode(args, encodingRules);
return assetData;
Expand All @@ -36,7 +35,7 @@ export const assetDataUtils = {
decodeERC20AssetData(assetData: string): ERC20AssetData {
assetDataUtils.assertIsERC20AssetData(assetData);
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI as MethodAbi);
const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI);
const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
return {
assetProxyId,
Expand All @@ -52,7 +51,7 @@ export const assetDataUtils = {
* @return The hex encoded assetData string
*/
encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string {
const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI as MethodAbi);
const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI);
const args = [tokenAddress, tokenId];
const assetData = abiEncoder.encode(args, encodingRules);
return assetData;
Expand All @@ -65,7 +64,7 @@ export const assetDataUtils = {
decodeERC721AssetData(assetData: string): ERC721AssetData {
assetDataUtils.assertIsERC721AssetData(assetData);
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI as MethodAbi);
const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI);
const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
return {
assetProxyId,
Expand All @@ -90,7 +89,7 @@ export const assetDataUtils = {
);
}
_.forEach(nestedAssetData, assetDataElement => assetDataUtils.validateAssetDataOrThrow(assetDataElement));
const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI as MethodAbi);
const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI);
const args = [amounts, nestedAssetData];
const assetData = abiEncoder.encode(args, encodingRules);
return assetData;
Expand All @@ -103,7 +102,7 @@ export const assetDataUtils = {
decodeMultiAssetData(assetData: string): MultiAssetData {
assetDataUtils.assertIsMultiAssetData(assetData);
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI as MethodAbi);
const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI);
const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
// TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion
const amounts = (decodedAssetData as any).amounts;
Expand Down Expand Up @@ -138,7 +137,7 @@ export const assetDataUtils = {
nestedAssetDataElement,
);
amounts.push(
_.map(recursivelyDecodedAssetData.amounts as BigNumber[], amountElement =>
_.map(recursivelyDecodedAssetData.amounts, amountElement =>
amountElement.times(decodedAssetData.amounts[index]),
),
);
Expand Down Expand Up @@ -181,6 +180,27 @@ export const assetDataUtils = {
}
return assetProxyId;
},
/**
* Checks if the decoded asset data is valid ERC20 data
* @param decodedAssetData The decoded asset data to check
*/
isERC20AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC20AssetData {
return decodedAssetData.assetProxyId === AssetProxyId.ERC20;
},
/**
* Checks if the decoded asset data is valid ERC721 data
* @param decodedAssetData The decoded asset data to check
*/
isERC721AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC721AssetData {
return decodedAssetData.assetProxyId === AssetProxyId.ERC721;
},
/**
* Checks if the decoded asset data is valid MultiAsset data
* @param decodedAssetData The decoded asset data to check
*/
isMultiAssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData {
return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset;
},
/**
* Throws if the length or assetProxyId are invalid for the ERC20Proxy.
* @param assetData Hex encoded assetData string
Expand Down
Loading

0 comments on commit d71196d

Please sign in to comment.