557 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			557 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import * as crypto from 'crypto';
 | 
						|
 | 
						|
import { artifacts as proxyArtifacts, TestStaticCallTargetContract } from '@0x/contracts-asset-proxy';
 | 
						|
import { artifacts, LibAssetDataContract } from '@0x/contracts-dev-utils';
 | 
						|
import { ERC1155MintableContract } from '@0x/contracts-erc1155';
 | 
						|
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
 | 
						|
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
 | 
						|
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
 | 
						|
import { AssetProxyId } from '@0x/types';
 | 
						|
import { BigNumber, hexUtils, LibBytesRevertErrors, StringRevertError } from '@0x/utils';
 | 
						|
 | 
						|
import { Actor } from '../framework/actors/base';
 | 
						|
import { DeploymentManager } from '../framework/deployment_manager';
 | 
						|
 | 
						|
const KNOWN_ERC20_ENCODING = {
 | 
						|
    address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
 | 
						|
    assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48',
 | 
						|
};
 | 
						|
const KNOWN_ERC721_ENCODING = {
 | 
						|
    address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
 | 
						|
    tokenId: new BigNumber(1),
 | 
						|
    assetData:
 | 
						|
        '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
 | 
						|
};
 | 
						|
const KNOWN_ERC1155_ENCODING = {
 | 
						|
    tokenAddress: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
 | 
						|
    tokenIds: [new BigNumber(100), new BigNumber(1001), new BigNumber(10001)],
 | 
						|
    tokenValues: [new BigNumber(200), new BigNumber(2001), new BigNumber(20001)],
 | 
						|
    callbackData:
 | 
						|
        '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
 | 
						|
    assetData:
 | 
						|
        '0xa7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000',
 | 
						|
};
 | 
						|
const KNOWN_MULTI_ASSET_ENCODING = {
 | 
						|
    amounts: [new BigNumber(70), new BigNumber(1), new BigNumber(18)],
 | 
						|
    nestedAssetData: [
 | 
						|
        KNOWN_ERC20_ENCODING.assetData,
 | 
						|
        KNOWN_ERC721_ENCODING.assetData,
 | 
						|
        KNOWN_ERC1155_ENCODING.assetData,
 | 
						|
    ],
 | 
						|
    assetData:
 | 
						|
        '0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204a7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c4800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
 | 
						|
};
 | 
						|
const KNOWN_STATIC_CALL_ENCODING = {
 | 
						|
    staticCallTargetAddress: '0x6dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f',
 | 
						|
    staticCallData: '0xed2cfc9c0000000000000000000000000000000000000000000000000000000000000001',
 | 
						|
    expectedReturnDataHash: '0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6',
 | 
						|
    assetData:
 | 
						|
        '0xc339d10a0000000000000000000000006dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f0000000000000000000000000000000000000000000000000000000000000060b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60000000000000000000000000000000000000000000000000000000000000024ed2cfc9c000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000',
 | 
						|
};
 | 
						|
 | 
						|
// TODO(jalextowle): This file could really be cleaned up by using the DeploymentManager tool.
 | 
						|
blockchainTests.resets('LibAssetData', env => {
 | 
						|
    let deployment: DeploymentManager;
 | 
						|
    let staticCallTarget: TestStaticCallTargetContract;
 | 
						|
    let libAssetData: LibAssetDataContract;
 | 
						|
 | 
						|
    let tokenOwner: Actor;
 | 
						|
 | 
						|
    let erc20Token: DummyERC20TokenContract;
 | 
						|
    let secondErc20Token: DummyERC20TokenContract;
 | 
						|
    let erc721Token: DummyERC721TokenContract;
 | 
						|
    let erc1155Token: ERC1155MintableContract;
 | 
						|
 | 
						|
    let erc721TokenId: BigNumber;
 | 
						|
    let erc1155TokenId: BigNumber;
 | 
						|
 | 
						|
    before(async () => {
 | 
						|
        deployment = await DeploymentManager.deployAsync(env, {
 | 
						|
            numErc20TokensToDeploy: 2,
 | 
						|
            numErc721TokensToDeploy: 1,
 | 
						|
            numErc1155TokensToDeploy: 1,
 | 
						|
        });
 | 
						|
        tokenOwner = new Actor({ name: 'Token Owner', deployment });
 | 
						|
 | 
						|
        libAssetData = await LibAssetDataContract.deployFrom0xArtifactAsync(
 | 
						|
            artifacts.LibAssetData,
 | 
						|
            env.provider,
 | 
						|
            env.txDefaults,
 | 
						|
            artifacts,
 | 
						|
            deployment.exchange.address,
 | 
						|
            constants.NULL_ADDRESS,
 | 
						|
        );
 | 
						|
 | 
						|
        staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
 | 
						|
            proxyArtifacts.TestStaticCallTarget,
 | 
						|
            env.provider,
 | 
						|
            env.txDefaults,
 | 
						|
            artifacts,
 | 
						|
        );
 | 
						|
 | 
						|
        [erc20Token, secondErc20Token] = deployment.tokens.erc20;
 | 
						|
        [erc721Token] = deployment.tokens.erc721;
 | 
						|
        [erc1155Token] = deployment.tokens.erc1155;
 | 
						|
 | 
						|
        // mint tokens
 | 
						|
        await tokenOwner.configureERC20TokenAsync(erc20Token);
 | 
						|
        [erc721TokenId] = await tokenOwner.configureERC721TokenAsync(erc721Token);
 | 
						|
        erc1155TokenId = await tokenOwner.configureERC1155TokenAsync(
 | 
						|
            erc1155Token,
 | 
						|
            deployment.assetProxies.erc1155Proxy.address,
 | 
						|
            new BigNumber(1),
 | 
						|
        );
 | 
						|
    });
 | 
						|
 | 
						|
    it('should have a deployed-to address', () => {
 | 
						|
        expect(libAssetData.address.slice(0, 2)).to.equal('0x');
 | 
						|
    });
 | 
						|
 | 
						|
    describe('encoding and decoding', () => {
 | 
						|
        it('should decode any asset proxy ID', async () => {
 | 
						|
            const assetDataScenarios = [
 | 
						|
                [KNOWN_ERC20_ENCODING.assetData, AssetProxyId.ERC20],
 | 
						|
                [KNOWN_ERC721_ENCODING.assetData, AssetProxyId.ERC721],
 | 
						|
                [KNOWN_ERC1155_ENCODING.assetData, AssetProxyId.ERC1155],
 | 
						|
                [KNOWN_MULTI_ASSET_ENCODING.assetData, AssetProxyId.MultiAsset],
 | 
						|
            ];
 | 
						|
 | 
						|
            for (const [assetData, proxyId] of assetDataScenarios) {
 | 
						|
                expect(await libAssetData.decodeAssetProxyId(assetData).callAsync()).to.equal(proxyId);
 | 
						|
            }
 | 
						|
        });
 | 
						|
        it('should encode ERC20 asset data', async () => {
 | 
						|
            expect(await libAssetData.encodeERC20AssetData(KNOWN_ERC20_ENCODING.address).callAsync()).to.equal(
 | 
						|
                KNOWN_ERC20_ENCODING.assetData,
 | 
						|
            );
 | 
						|
        });
 | 
						|
 | 
						|
        it('should decode ERC20 asset data', async () => {
 | 
						|
            expect(await libAssetData.decodeERC20AssetData(KNOWN_ERC20_ENCODING.assetData).callAsync()).to.deep.equal([
 | 
						|
                AssetProxyId.ERC20,
 | 
						|
                KNOWN_ERC20_ENCODING.address,
 | 
						|
            ]);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should encode ERC721 asset data', async () => {
 | 
						|
            expect(
 | 
						|
                await libAssetData
 | 
						|
                    .encodeERC721AssetData(KNOWN_ERC721_ENCODING.address, KNOWN_ERC721_ENCODING.tokenId)
 | 
						|
                    .callAsync(),
 | 
						|
            ).to.equal(KNOWN_ERC721_ENCODING.assetData);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should decode ERC721 asset data', async () => {
 | 
						|
            expect(await libAssetData.decodeERC721AssetData(KNOWN_ERC721_ENCODING.assetData).callAsync()).to.deep.equal(
 | 
						|
                [AssetProxyId.ERC721, KNOWN_ERC721_ENCODING.address, KNOWN_ERC721_ENCODING.tokenId],
 | 
						|
            );
 | 
						|
        });
 | 
						|
 | 
						|
        it('should encode ERC1155 asset data', async () => {
 | 
						|
            expect(
 | 
						|
                await libAssetData
 | 
						|
                    .encodeERC1155AssetData(
 | 
						|
                        KNOWN_ERC1155_ENCODING.tokenAddress,
 | 
						|
                        KNOWN_ERC1155_ENCODING.tokenIds,
 | 
						|
                        KNOWN_ERC1155_ENCODING.tokenValues,
 | 
						|
                        KNOWN_ERC1155_ENCODING.callbackData,
 | 
						|
                    )
 | 
						|
                    .callAsync(),
 | 
						|
            ).to.equal(KNOWN_ERC1155_ENCODING.assetData);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should decode ERC1155 asset data', async () => {
 | 
						|
            expect(
 | 
						|
                await libAssetData.decodeERC1155AssetData(KNOWN_ERC1155_ENCODING.assetData).callAsync(),
 | 
						|
            ).to.deep.equal([
 | 
						|
                AssetProxyId.ERC1155,
 | 
						|
                KNOWN_ERC1155_ENCODING.tokenAddress,
 | 
						|
                KNOWN_ERC1155_ENCODING.tokenIds,
 | 
						|
                KNOWN_ERC1155_ENCODING.tokenValues,
 | 
						|
                KNOWN_ERC1155_ENCODING.callbackData,
 | 
						|
            ]);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should encode multiasset data', async () => {
 | 
						|
            expect(
 | 
						|
                await libAssetData
 | 
						|
                    .encodeMultiAssetData(
 | 
						|
                        KNOWN_MULTI_ASSET_ENCODING.amounts,
 | 
						|
                        KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
 | 
						|
                    )
 | 
						|
                    .callAsync(),
 | 
						|
            ).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should decode multiasset data', async () => {
 | 
						|
            expect(
 | 
						|
                await libAssetData.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData).callAsync(),
 | 
						|
            ).to.deep.equal([
 | 
						|
                AssetProxyId.MultiAsset,
 | 
						|
                KNOWN_MULTI_ASSET_ENCODING.amounts,
 | 
						|
                KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
 | 
						|
            ]);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should encode StaticCall data', async () => {
 | 
						|
            expect(
 | 
						|
                await libAssetData
 | 
						|
                    .encodeStaticCallAssetData(
 | 
						|
                        KNOWN_STATIC_CALL_ENCODING.staticCallTargetAddress,
 | 
						|
                        KNOWN_STATIC_CALL_ENCODING.staticCallData,
 | 
						|
                        KNOWN_STATIC_CALL_ENCODING.expectedReturnDataHash,
 | 
						|
                    )
 | 
						|
                    .callAsync(),
 | 
						|
            ).to.equal(KNOWN_STATIC_CALL_ENCODING.assetData);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should decode StaticCall data', async () => {
 | 
						|
            expect(
 | 
						|
                await libAssetData.decodeStaticCallAssetData(KNOWN_STATIC_CALL_ENCODING.assetData).callAsync(),
 | 
						|
            ).to.deep.equal([
 | 
						|
                AssetProxyId.StaticCall,
 | 
						|
                KNOWN_STATIC_CALL_ENCODING.staticCallTargetAddress,
 | 
						|
                KNOWN_STATIC_CALL_ENCODING.staticCallData,
 | 
						|
                KNOWN_STATIC_CALL_ENCODING.expectedReturnDataHash,
 | 
						|
            ]);
 | 
						|
        });
 | 
						|
    });
 | 
						|
    describe('revertIfInvalidAssetData', async () => {
 | 
						|
        it('should succeed for any valid asset data', async () => {
 | 
						|
            const assetData = [
 | 
						|
                KNOWN_ERC20_ENCODING.assetData,
 | 
						|
                KNOWN_ERC721_ENCODING.assetData,
 | 
						|
                KNOWN_ERC1155_ENCODING.assetData,
 | 
						|
                KNOWN_MULTI_ASSET_ENCODING.assetData,
 | 
						|
                KNOWN_STATIC_CALL_ENCODING.assetData,
 | 
						|
            ];
 | 
						|
 | 
						|
            for (const data of assetData) {
 | 
						|
                await libAssetData.revertIfInvalidAssetData(data).callAsync();
 | 
						|
            }
 | 
						|
            return;
 | 
						|
        });
 | 
						|
 | 
						|
        it('should revert for invalid assetProxyId', async () => {
 | 
						|
            const badAssetData = `0x${crypto.randomBytes(4).toString('hex')}${constants.NULL_ADDRESS}`;
 | 
						|
            await expect(libAssetData.revertIfInvalidAssetData(badAssetData).callAsync()).to.eventually.be.rejectedWith(
 | 
						|
                StringRevertError,
 | 
						|
            );
 | 
						|
        });
 | 
						|
 | 
						|
        it('should revert for invalid assetData with valid assetProxyId', async () => {
 | 
						|
            // the other encodings are always valid if the assetProxyId is valid
 | 
						|
            const assetData = [KNOWN_ERC20_ENCODING.assetData, KNOWN_ERC721_ENCODING.assetData];
 | 
						|
 | 
						|
            for (const data of assetData) {
 | 
						|
                const badData = data.substring(0, data.length - 2); // drop one byte but retain assetProxyId
 | 
						|
                await expect(libAssetData.revertIfInvalidAssetData(badData).callAsync()).to.eventually.be.rejectedWith(
 | 
						|
                    LibBytesRevertErrors.InvalidByteOperationError,
 | 
						|
                );
 | 
						|
            }
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('getBalance', () => {
 | 
						|
        it('should query ERC20 balance by asset data', async () => {
 | 
						|
            const assetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
 | 
						|
            expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
 | 
						|
                constants.INITIAL_ERC20_BALANCE,
 | 
						|
            );
 | 
						|
        });
 | 
						|
 | 
						|
        it('should return 0 if ERC20 token does not exist', async () => {
 | 
						|
            const assetData = await libAssetData.encodeERC20AssetData(constants.NULL_ADDRESS).callAsync();
 | 
						|
            const balance = await libAssetData.getBalance(tokenOwner.address, assetData).callAsync();
 | 
						|
            expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should query ERC721 balance by asset data', async () => {
 | 
						|
            const assetData = await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync();
 | 
						|
            expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should return 0 if ERC721 token does not exist', async () => {
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeERC721AssetData(constants.NULL_ADDRESS, erc721TokenId)
 | 
						|
                .callAsync();
 | 
						|
            const balance = await libAssetData.getBalance(tokenOwner.address, assetData).callAsync();
 | 
						|
            expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should query ERC1155 balances by asset data', async () => {
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeERC1155AssetData(
 | 
						|
                    erc1155Token.address,
 | 
						|
                    [erc1155TokenId],
 | 
						|
                    [new BigNumber(1)],
 | 
						|
                    constants.NULL_BYTES,
 | 
						|
                )
 | 
						|
                .callAsync();
 | 
						|
            expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should return 0 if ERC1155 token does not exist', async () => {
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeERC1155AssetData(
 | 
						|
                    constants.NULL_ADDRESS,
 | 
						|
                    [erc1155TokenId],
 | 
						|
                    [new BigNumber(1)],
 | 
						|
                    constants.NULL_BYTES,
 | 
						|
                )
 | 
						|
                .callAsync();
 | 
						|
            const balance = await libAssetData.getBalance(tokenOwner.address, assetData).callAsync();
 | 
						|
            expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should query multi-asset batch balance by asset data', async () => {
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeMultiAssetData(
 | 
						|
                    [new BigNumber(1), new BigNumber(1)],
 | 
						|
                    [
 | 
						|
                        await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
 | 
						|
                        await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
 | 
						|
                    ],
 | 
						|
                )
 | 
						|
                .callAsync();
 | 
						|
            expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should query multi-asset batch balance by asset data, skipping over a nested asset if its amount == 0', async () => {
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeMultiAssetData(
 | 
						|
                    [constants.ZERO_AMOUNT, new BigNumber(1)],
 | 
						|
                    [
 | 
						|
                        await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
 | 
						|
                        await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
 | 
						|
                    ],
 | 
						|
                )
 | 
						|
                .callAsync();
 | 
						|
            expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should return a balance of 0 if the balance for a nested asset is 0', async () => {
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeMultiAssetData(
 | 
						|
                    [new BigNumber(1), new BigNumber(1)],
 | 
						|
                    [
 | 
						|
                        await libAssetData.encodeERC20AssetData(secondErc20Token.address).callAsync(),
 | 
						|
                        await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
 | 
						|
                    ],
 | 
						|
                )
 | 
						|
                .callAsync();
 | 
						|
            expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
 | 
						|
                constants.ZERO_AMOUNT,
 | 
						|
            );
 | 
						|
        });
 | 
						|
 | 
						|
        it('should return a balance of 0 if the assetData does not correspond to an AssetProxy contract', async () => {
 | 
						|
            const fakeAssetData = '0x01020304';
 | 
						|
            const balance = await libAssetData.getBalance(tokenOwner.address, fakeAssetData).callAsync();
 | 
						|
            expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should return a balance of MAX_UINT256 if the the StaticCallProxy assetData contains data for a successful staticcall', async () => {
 | 
						|
            const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData();
 | 
						|
            const expectedResultHash = hexUtils.hash(hexUtils.leftPad(1));
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
 | 
						|
                .callAsync();
 | 
						|
            const balance = await libAssetData.getBalance(tokenOwner.address, assetData).callAsync();
 | 
						|
            expect(balance).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should return a balance of 0 if the the StaticCallProxy assetData contains data for an unsuccessful staticcall', async () => {
 | 
						|
            const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData();
 | 
						|
            const expectedResultHash = hexUtils.hash(hexUtils.leftPad(1));
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
 | 
						|
                .callAsync();
 | 
						|
            const balance = await libAssetData.getBalance(tokenOwner.address, assetData).callAsync();
 | 
						|
            expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('getAssetProxyAllowance', () => {
 | 
						|
        it('should query ERC20 allowances by asset data', async () => {
 | 
						|
            const assetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
 | 
						|
            ).to.bignumber.equal(constants.MAX_UINT256);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should query ERC721 approval by asset data', async () => {
 | 
						|
            // Temporarily remove approval for all
 | 
						|
            await erc721Token
 | 
						|
                .setApprovalForAll(deployment.assetProxies.erc721Proxy.address, false)
 | 
						|
                .awaitTransactionSuccessAsync({ from: tokenOwner.address });
 | 
						|
            await erc721Token
 | 
						|
                .approve(deployment.assetProxies.erc721Proxy.address, erc721TokenId)
 | 
						|
                .awaitTransactionSuccessAsync({
 | 
						|
                    from: tokenOwner.address,
 | 
						|
                });
 | 
						|
            const assetData = await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
 | 
						|
            ).to.bignumber.equal(1);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should query ERC721 approvalForAll by assetData', async () => {
 | 
						|
            const assetData = await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
 | 
						|
            ).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should query ERC1155 allowances by asset data', async () => {
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeERC1155AssetData(
 | 
						|
                    erc1155Token.address,
 | 
						|
                    [erc1155TokenId],
 | 
						|
                    [new BigNumber(1)],
 | 
						|
                    constants.NULL_BYTES,
 | 
						|
                )
 | 
						|
                .callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
 | 
						|
            ).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should query multi-asset allowances by asset data', async () => {
 | 
						|
            const allowance = new BigNumber(1);
 | 
						|
            await erc20Token
 | 
						|
                .approve(deployment.assetProxies.erc20Proxy.address, allowance)
 | 
						|
                .awaitTransactionSuccessAsync({
 | 
						|
                    from: tokenOwner.address,
 | 
						|
                });
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeMultiAssetData(
 | 
						|
                    [new BigNumber(1), new BigNumber(1)],
 | 
						|
                    [
 | 
						|
                        await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
 | 
						|
                        await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
 | 
						|
                    ],
 | 
						|
                )
 | 
						|
                .callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
 | 
						|
            ).to.bignumber.equal(1);
 | 
						|
            return;
 | 
						|
        });
 | 
						|
 | 
						|
        it('should query multi-asset allowances by asset data, skipping over a nested asset if its amount == 0', async () => {
 | 
						|
            const allowance = new BigNumber(1);
 | 
						|
            await erc20Token
 | 
						|
                .approve(deployment.assetProxies.erc20Proxy.address, allowance)
 | 
						|
                .awaitTransactionSuccessAsync({
 | 
						|
                    from: tokenOwner.address,
 | 
						|
                });
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeMultiAssetData(
 | 
						|
                    [constants.ZERO_AMOUNT, new BigNumber(1)],
 | 
						|
                    [
 | 
						|
                        await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
 | 
						|
                        await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
 | 
						|
                    ],
 | 
						|
                )
 | 
						|
                .callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
 | 
						|
            ).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
 | 
						|
            return;
 | 
						|
        });
 | 
						|
 | 
						|
        it('should return an allowance of 0 if the allowance for a nested asset is 0', async () => {
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeMultiAssetData(
 | 
						|
                    [new BigNumber(1), new BigNumber(1)],
 | 
						|
                    [
 | 
						|
                        await libAssetData.encodeERC20AssetData(secondErc20Token.address).callAsync(),
 | 
						|
                        await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
 | 
						|
                    ],
 | 
						|
                )
 | 
						|
                .callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
 | 
						|
            ).to.bignumber.equal(constants.ZERO_AMOUNT);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should return an allowance of 0 if the assetData does not correspond to an AssetProxy contract', async () => {
 | 
						|
            const fakeAssetData = '0x01020304';
 | 
						|
            const allowance = await libAssetData.getAssetProxyAllowance(tokenOwner.address, fakeAssetData).callAsync();
 | 
						|
            expect(allowance).to.bignumber.equal(constants.ZERO_AMOUNT);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should return an allowance of MAX_UINT256 for any staticCallAssetData', async () => {
 | 
						|
            const staticCallData = AssetProxyId.StaticCall;
 | 
						|
            const assetData = await libAssetData
 | 
						|
                .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, constants.KECCAK256_NULL)
 | 
						|
                .callAsync();
 | 
						|
            const allowance = await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync();
 | 
						|
            expect(allowance).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('getBatchBalances', () => {
 | 
						|
        it('should query balances for a batch of asset data strings', async () => {
 | 
						|
            const erc20AssetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
 | 
						|
            const erc721AssetData = await libAssetData
 | 
						|
                .encodeERC721AssetData(erc721Token.address, erc721TokenId)
 | 
						|
                .callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData.getBatchBalances(tokenOwner.address, [erc20AssetData, erc721AssetData]).callAsync(),
 | 
						|
            ).to.deep.equal([new BigNumber(constants.INITIAL_ERC20_BALANCE), new BigNumber(1)]);
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('getBalanceAndAllowance', () => {
 | 
						|
        it('should query balance and allowance together, from asset data', async () => {
 | 
						|
            const allowance = new BigNumber(1);
 | 
						|
            await erc20Token
 | 
						|
                .approve(deployment.assetProxies.erc20Proxy.address, allowance)
 | 
						|
                .awaitTransactionSuccessAsync({
 | 
						|
                    from: tokenOwner.address,
 | 
						|
                });
 | 
						|
            const assetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData.getBalanceAndAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
 | 
						|
            ).to.deep.equal([new BigNumber(constants.INITIAL_ERC20_BALANCE), allowance]);
 | 
						|
        });
 | 
						|
    });
 | 
						|
    describe('getBatchBalancesAndAllowances', () => {
 | 
						|
        it('should query balances and allowances together, from an asset data array', async () => {
 | 
						|
            const allowance = new BigNumber(1);
 | 
						|
            await erc20Token
 | 
						|
                .approve(deployment.assetProxies.erc20Proxy.address, allowance)
 | 
						|
                .awaitTransactionSuccessAsync({
 | 
						|
                    from: tokenOwner.address,
 | 
						|
                });
 | 
						|
            const assetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData.getBatchBalancesAndAssetProxyAllowances(tokenOwner.address, [assetData]).callAsync(),
 | 
						|
            ).to.deep.equal([[new BigNumber(constants.INITIAL_ERC20_BALANCE)], [allowance]]);
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('getBatchAssetProxyAllowances', () => {
 | 
						|
        it('should query allowances for a batch of asset data strings', async () => {
 | 
						|
            const allowance = new BigNumber(1);
 | 
						|
            await erc20Token
 | 
						|
                .approve(deployment.assetProxies.erc20Proxy.address, allowance)
 | 
						|
                .awaitTransactionSuccessAsync({
 | 
						|
                    from: tokenOwner.address,
 | 
						|
                });
 | 
						|
            const erc20AssetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
 | 
						|
            const erc721AssetData = await libAssetData
 | 
						|
                .encodeERC721AssetData(erc721Token.address, erc721TokenId)
 | 
						|
                .callAsync();
 | 
						|
            expect(
 | 
						|
                await libAssetData
 | 
						|
                    .getBatchAssetProxyAllowances(tokenOwner.address, [erc20AssetData, erc721AssetData])
 | 
						|
                    .callAsync(),
 | 
						|
            ).to.deep.equal([allowance, constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS]);
 | 
						|
        });
 | 
						|
    });
 | 
						|
});
 | 
						|
// tslint:disable:max-file-line-count
 |