Fix transferFrom to work with MAP

This commit is contained in:
Amir Bandeali 2018-12-04 15:44:46 -08:00
parent 0abace337c
commit eeb07d76fc
3 changed files with 48 additions and 21 deletions

View File

@ -1,7 +1,8 @@
import { ExchangeContractErrs } from '@0x/types'; import { AssetProxyId, ExchangeContractErrs } from '@0x/types';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import { AbstractBalanceAndProxyAllowanceLazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store'; import { AbstractBalanceAndProxyAllowanceLazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store';
import { assetDataUtils } from './asset_data_utils';
import { constants } from './constants'; import { constants } from './constants';
import { TradeSide, TransferType } from './types'; import { TradeSide, TransferType } from './types';
@ -74,24 +75,51 @@ export class ExchangeTransferSimulator {
tradeSide: TradeSide, tradeSide: TradeSide,
transferType: TransferType, transferType: TransferType,
): Promise<void> { ): Promise<void> {
// HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
// allowances for the taker. We do however, want to increase the balance of the maker since the maker switch (assetProxyId) {
// might be relying on those funds to fill subsequent orders or pay the order's fees. case AssetProxyId.ERC20:
if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) { case AssetProxyId.ERC721:
await this._increaseBalanceAsync(assetData, to, amountInBaseUnits); // HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/
return; // allowances for the taker. We do however, want to increase the balance of the maker since the maker
// might be relying on those funds to fill subsequent orders or pay the order's fees.
if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) {
await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
return;
}
const balance = await this._store.getBalanceAsync(assetData, from);
const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, from);
if (proxyAllowance.lessThan(amountInBaseUnits)) {
ExchangeTransferSimulator._throwValidationError(
FailureReason.ProxyAllowance,
tradeSide,
transferType,
);
}
if (balance.lessThan(amountInBaseUnits)) {
ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
}
await this._decreaseProxyAllowanceAsync(assetData, from, amountInBaseUnits);
await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits);
await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
break;
case AssetProxyId.MultiAsset:
const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
const amountsElement = decodedAssetData.amounts[index];
const totalAmount = amountInBaseUnits.times(amountsElement);
await this.transferFromAsync(
nestedAssetDataElement,
from,
to,
totalAmount,
tradeSide,
transferType,
);
}
break;
default:
break;
} }
const balance = await this._store.getBalanceAsync(assetData, from);
const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, from);
if (proxyAllowance.lessThan(amountInBaseUnits)) {
ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
}
if (balance.lessThan(amountInBaseUnits)) {
ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
}
await this._decreaseProxyAllowanceAsync(assetData, from, amountInBaseUnits);
await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits);
await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
} }
private async _decreaseProxyAllowanceAsync( private async _decreaseProxyAllowanceAsync(
assetData: string, assetData: string,

View File

@ -50,14 +50,14 @@ describe('assetDataUtils', () => {
expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC721); expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC721);
expect(decodedAssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId); expect(decodedAssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
}); });
it('should encode ERC20 and ERC721', () => { it('should encode ERC20 and ERC721 multiAssetData', () => {
const assetData = assetDataUtils.encodeMultiAssetData( const assetData = assetDataUtils.encodeMultiAssetData(
KNOWN_MULTI_ASSET_ENCODING.amounts, KNOWN_MULTI_ASSET_ENCODING.amounts,
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData, KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
); );
expect(assetData).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData); expect(assetData).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData);
}); });
it('should decode ERC20 and ERC21', () => { it('should decode ERC20 and ERC721 multiAssetData', () => {
const decodedAssetData = assetDataUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData); const decodedAssetData = assetDataUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData);
expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset); expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts); expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts);

View File

@ -75,7 +75,6 @@ export class DependentOrderHashesTracker {
} }
this._removeFromMakerDependentOrderhashes(signedOrder); this._removeFromMakerDependentOrderhashes(signedOrder);
} }
private _getDependentOrderHashesByERC20AssetData(makerAddress: string, erc20AssetData: string): string[] { private _getDependentOrderHashesByERC20AssetData(makerAddress: string, erc20AssetData: string): string[] {
const tokenAddress = assetDataUtils.decodeERC20AssetData(erc20AssetData).tokenAddress; const tokenAddress = assetDataUtils.decodeERC20AssetData(erc20AssetData).tokenAddress;
let dependentOrderHashes: string[] = []; let dependentOrderHashes: string[] = [];