Add StaticCallAssetData encoding and decoding
This commit is contained in:
		@@ -1,13 +1,13 @@
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
    AssetProxyId,
 | 
					    AssetProxyId,
 | 
				
			||||||
    ERC1155AssetData,
 | 
					    ERC1155AssetData,
 | 
				
			||||||
    ERC1155AssetDataAbi,
 | 
					 | 
				
			||||||
    ERC1155AssetDataNoProxyId,
 | 
					    ERC1155AssetDataNoProxyId,
 | 
				
			||||||
    ERC20AssetData,
 | 
					    ERC20AssetData,
 | 
				
			||||||
    ERC721AssetData,
 | 
					    ERC721AssetData,
 | 
				
			||||||
    MultiAssetData,
 | 
					    MultiAssetData,
 | 
				
			||||||
    MultiAssetDataWithRecursiveDecoding,
 | 
					    MultiAssetDataWithRecursiveDecoding,
 | 
				
			||||||
    SingleAssetData,
 | 
					    SingleAssetData,
 | 
				
			||||||
 | 
					    StaticCallAssetData,
 | 
				
			||||||
} from '@0x/types';
 | 
					} from '@0x/types';
 | 
				
			||||||
import { AbiEncoder, BigNumber } from '@0x/utils';
 | 
					import { AbiEncoder, BigNumber } from '@0x/utils';
 | 
				
			||||||
import * as _ from 'lodash';
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
@@ -31,7 +31,7 @@ export const assetDataUtils = {
 | 
				
			|||||||
        return assetData;
 | 
					        return assetData;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Decodes an ERC20 assetData hex string into it's corresponding ERC20 tokenAddress & assetProxyId
 | 
					     * Decodes an ERC20 assetData hex string into its corresponding ERC20 tokenAddress & assetProxyId
 | 
				
			||||||
     * @param assetData Hex encoded assetData string to decode
 | 
					     * @param assetData Hex encoded assetData string to decode
 | 
				
			||||||
     * @return An object containing the decoded tokenAddress & assetProxyId
 | 
					     * @return An object containing the decoded tokenAddress & assetProxyId
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -60,7 +60,7 @@ export const assetDataUtils = {
 | 
				
			|||||||
        return assetData;
 | 
					        return assetData;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Decodes an ERC721 assetData hex string into it's corresponding ERC721 tokenAddress, tokenId & assetProxyId
 | 
					     * Decodes an ERC721 assetData hex string into its corresponding ERC721 tokenAddress, tokenId & assetProxyId
 | 
				
			||||||
     * @param assetData Hex encoded assetData string to decode
 | 
					     * @param assetData Hex encoded assetData string to decode
 | 
				
			||||||
     * @return An object containing the decoded tokenAddress, tokenId & assetProxyId
 | 
					     * @return An object containing the decoded tokenAddress, tokenId & assetProxyId
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -91,13 +91,13 @@ export const assetDataUtils = {
 | 
				
			|||||||
        tokenValues: BigNumber[],
 | 
					        tokenValues: BigNumber[],
 | 
				
			||||||
        callbackData: string,
 | 
					        callbackData: string,
 | 
				
			||||||
    ): string {
 | 
					    ): string {
 | 
				
			||||||
        const abiEncoder = AbiEncoder.createMethod('ERC1155Assets', ERC1155AssetDataAbi);
 | 
					        const abiEncoder = AbiEncoder.createMethod('ERC1155Assets', constants.ERC1155_METHOD_ABI.inputs);
 | 
				
			||||||
        const args = [tokenAddress, tokenIds, tokenValues, callbackData];
 | 
					        const args = [tokenAddress, tokenIds, tokenValues, callbackData];
 | 
				
			||||||
        const assetData = abiEncoder.encode(args, encodingRules);
 | 
					        const assetData = abiEncoder.encode(args, encodingRules);
 | 
				
			||||||
        return assetData;
 | 
					        return assetData;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Decodes an ERC1155 assetData hex string into it's corresponding ERC1155 components.
 | 
					     * Decodes an ERC1155 assetData hex string into its corresponding ERC1155 components.
 | 
				
			||||||
     * @param assetData Hex encoded assetData string to decode
 | 
					     * @param assetData Hex encoded assetData string to decode
 | 
				
			||||||
     * @return An object containing the decoded tokenAddress, tokenIds, tokenValues, callbackData & assetProxyId
 | 
					     * @return An object containing the decoded tokenAddress, tokenIds, tokenValues, callbackData & assetProxyId
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -106,7 +106,7 @@ export const assetDataUtils = {
 | 
				
			|||||||
        if (assetProxyId !== AssetProxyId.ERC1155) {
 | 
					        if (assetProxyId !== AssetProxyId.ERC1155) {
 | 
				
			||||||
            throw new Error(`Invalid assetProxyId. Expected '${AssetProxyId.ERC1155}', got '${assetProxyId}'`);
 | 
					            throw new Error(`Invalid assetProxyId. Expected '${AssetProxyId.ERC1155}', got '${assetProxyId}'`);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const abiEncoder = AbiEncoder.createMethod('ERC1155Assets', ERC1155AssetDataAbi);
 | 
					        const abiEncoder = AbiEncoder.createMethod('ERC1155Assets', constants.ERC1155_METHOD_ABI.inputs);
 | 
				
			||||||
        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
					        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
				
			||||||
        const decodedAssetData = abiEncoder.decode(assetData, decodingRules) as ERC1155AssetDataNoProxyId;
 | 
					        const decodedAssetData = abiEncoder.decode(assetData, decodingRules) as ERC1155AssetDataNoProxyId;
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
@@ -139,7 +139,7 @@ export const assetDataUtils = {
 | 
				
			|||||||
        return assetData;
 | 
					        return assetData;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Decodes a MultiAsset assetData hex string into it's corresponding amounts and nestedAssetData
 | 
					     * Decodes a MultiAsset assetData hex string into its corresponding amounts and nestedAssetData
 | 
				
			||||||
     * @param assetData Hex encoded assetData string to decode
 | 
					     * @param assetData Hex encoded assetData string to decode
 | 
				
			||||||
     * @return An object containing the decoded amounts and nestedAssetData
 | 
					     * @return An object containing the decoded amounts and nestedAssetData
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -165,7 +165,7 @@ export const assetDataUtils = {
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Decodes a MultiAsset assetData hex string into it's corresponding amounts and decoded nestedAssetData elements (all nested elements are flattened)
 | 
					     * Decodes a MultiAsset assetData hex string into its corresponding amounts and decoded nestedAssetData elements (all nested elements are flattened)
 | 
				
			||||||
     * @param assetData Hex encoded assetData string to decode
 | 
					     * @param assetData Hex encoded assetData string to decode
 | 
				
			||||||
     * @return An object containing the decoded amounts and nestedAssetData
 | 
					     * @return An object containing the decoded amounts and nestedAssetData
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -201,6 +201,35 @@ export const assetDataUtils = {
 | 
				
			|||||||
            nestedAssetData: flattenedDecodedNestedAssetData as SingleAssetData[],
 | 
					            nestedAssetData: flattenedDecodedNestedAssetData as SingleAssetData[],
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Encodes StaticCallProxy data into an assetData hex string
 | 
				
			||||||
 | 
					     * @param callTarget Address of contract to call from StaticCallProxy
 | 
				
			||||||
 | 
					     * @param staticCallData The function data that will be called on the callTarget contract
 | 
				
			||||||
 | 
					     * @param callResultHash The keccak256 hash of the ABI encoded expected output of the static call
 | 
				
			||||||
 | 
					     * @return The hex encoded assetData string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    encodeStaticCallAssetData(callTarget: string, staticCallData: string, callResultHash: string): string {
 | 
				
			||||||
 | 
					        const abiEncoder = AbiEncoder.createMethod('StaticCall', constants.STATIC_CALL_METHOD_ABI.inputs);
 | 
				
			||||||
 | 
					        const args = [callTarget, staticCallData, callResultHash];
 | 
				
			||||||
 | 
					        const assetData = abiEncoder.encode(args, encodingRules);
 | 
				
			||||||
 | 
					        return assetData;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Decoded StaticCall assetData into its corresponding callTarget, staticCallData, and expected callResultHash
 | 
				
			||||||
 | 
					     * @param assetData Hex encoded assetData string to decode
 | 
				
			||||||
 | 
					     * @return An object containing the decoded callTarget, staticCallData, and expected callResultHash
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    decodeStaticCallAssetData(assetData: string): StaticCallAssetData {
 | 
				
			||||||
 | 
					        const abiEncoder = AbiEncoder.createMethod('StaticCall', constants.STATIC_CALL_METHOD_ABI.inputs);
 | 
				
			||||||
 | 
					        const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
 | 
				
			||||||
 | 
					        const decodedAssetData = abiEncoder.decode(assetData, decodingRules) as any;
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            assetProxyId,
 | 
				
			||||||
 | 
					            callTarget: decodedAssetData.callTarget,
 | 
				
			||||||
 | 
					            callResultHash: decodedAssetData.callResultHash,
 | 
				
			||||||
 | 
					            staticCallData: decodedAssetData.staticCallData,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Decode and return the assetProxyId from the assetData
 | 
					     * Decode and return the assetProxyId from the assetData
 | 
				
			||||||
     * @param assetData Hex encoded assetData string to decode
 | 
					     * @param assetData Hex encoded assetData string to decode
 | 
				
			||||||
@@ -219,6 +248,7 @@ export const assetDataUtils = {
 | 
				
			|||||||
            assetProxyId !== AssetProxyId.ERC20 &&
 | 
					            assetProxyId !== AssetProxyId.ERC20 &&
 | 
				
			||||||
            assetProxyId !== AssetProxyId.ERC721 &&
 | 
					            assetProxyId !== AssetProxyId.ERC721 &&
 | 
				
			||||||
            assetProxyId !== AssetProxyId.ERC1155 &&
 | 
					            assetProxyId !== AssetProxyId.ERC1155 &&
 | 
				
			||||||
 | 
					            assetProxyId !== AssetProxyId.StaticCall &&
 | 
				
			||||||
            assetProxyId !== AssetProxyId.MultiAsset
 | 
					            assetProxyId !== AssetProxyId.MultiAsset
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            throw new Error(`Invalid assetProxyId: ${assetProxyId}`);
 | 
					            throw new Error(`Invalid assetProxyId: ${assetProxyId}`);
 | 
				
			||||||
@@ -253,6 +283,13 @@ export const assetDataUtils = {
 | 
				
			|||||||
    isMultiAssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData {
 | 
					    isMultiAssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData {
 | 
				
			||||||
        return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset;
 | 
					        return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks if the decoded asset data is valid StaticCall data
 | 
				
			||||||
 | 
					     * @param decodedAssetData The decoded asset data to check
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isStaticCallAssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is StaticCallAssetData {
 | 
				
			||||||
 | 
					        return decodedAssetData.assetProxyId === AssetProxyId.StaticCall;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Throws if the length or assetProxyId are invalid for the ERC20Proxy.
 | 
					     * Throws if the length or assetProxyId are invalid for the ERC20Proxy.
 | 
				
			||||||
     * @param assetData Hex encoded assetData string
 | 
					     * @param assetData Hex encoded assetData string
 | 
				
			||||||
@@ -324,6 +361,13 @@ export const assetDataUtils = {
 | 
				
			|||||||
            );
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Throws if the assetData is not StaticCallData.
 | 
				
			||||||
 | 
					     * @param assetData Hex encoded assetData string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    assertIsStaticCallAssetData(assetData: string): void {
 | 
				
			||||||
 | 
					        assetDataUtils.decodeStaticCallAssetData(assetData);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Throws if the length or assetProxyId are invalid for the corresponding AssetProxy.
 | 
					     * Throws if the length or assetProxyId are invalid for the corresponding AssetProxy.
 | 
				
			||||||
     * @param assetData Hex encoded assetData string
 | 
					     * @param assetData Hex encoded assetData string
 | 
				
			||||||
@@ -348,7 +392,7 @@ export const assetDataUtils = {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Decode any assetData into it's corresponding assetData object
 | 
					     * Decode any assetData into its corresponding assetData object
 | 
				
			||||||
     * @param assetData Hex encoded assetData string to decode
 | 
					     * @param assetData Hex encoded assetData string to decode
 | 
				
			||||||
     * @return Either a ERC20, ERC721, ERC1155, or MultiAsset assetData object
 | 
					     * @return Either a ERC20, ERC721, ERC1155, or MultiAsset assetData object
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,7 +48,6 @@ export {
 | 
				
			|||||||
    ERC20AssetData,
 | 
					    ERC20AssetData,
 | 
				
			||||||
    ERC721AssetData,
 | 
					    ERC721AssetData,
 | 
				
			||||||
    ERC1155AssetData,
 | 
					    ERC1155AssetData,
 | 
				
			||||||
    ERC1155AssetDataAbi,
 | 
					 | 
				
			||||||
    MultiAssetData,
 | 
					    MultiAssetData,
 | 
				
			||||||
    MultiAssetDataWithRecursiveDecoding,
 | 
					    MultiAssetDataWithRecursiveDecoding,
 | 
				
			||||||
    AssetProxyId,
 | 
					    AssetProxyId,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import * as chai from 'chai';
 | 
					import * as chai from 'chai';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { AssetProxyId, ERC1155AssetData, ERC721AssetData } from '@0x/types';
 | 
					import { AssetProxyId, ERC1155AssetData, ERC20AssetData, ERC721AssetData } from '@0x/types';
 | 
				
			||||||
import { BigNumber } from '@0x/utils';
 | 
					import { BigNumber } from '@0x/utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { assetDataUtils } from '../src/asset_data_utils';
 | 
					import { assetDataUtils } from '../src/asset_data_utils';
 | 
				
			||||||
@@ -98,7 +98,8 @@ describe('assetDataUtils', () => {
 | 
				
			|||||||
        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);
 | 
				
			||||||
        expect(decodedAssetData.nestedAssetData.length).to.equal(3);
 | 
					        expect(decodedAssetData.nestedAssetData.length).to.equal(3);
 | 
				
			||||||
        const decodedErc20AssetData = decodedAssetData.nestedAssetData[0];
 | 
					        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
				
			||||||
 | 
					        const decodedErc20AssetData = decodedAssetData.nestedAssetData[0] as ERC20AssetData;
 | 
				
			||||||
        expect(decodedErc20AssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
 | 
					        expect(decodedErc20AssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
 | 
				
			||||||
        expect(decodedErc20AssetData.assetProxyId).to.equal(AssetProxyId.ERC20);
 | 
					        expect(decodedErc20AssetData.assetProxyId).to.equal(AssetProxyId.ERC20);
 | 
				
			||||||
        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
					        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
				
			||||||
@@ -144,7 +145,8 @@ describe('assetDataUtils', () => {
 | 
				
			|||||||
        expect(decodedAssetData.nestedAssetData.length).to.be.equal(expectedNestedAssetDataLength);
 | 
					        expect(decodedAssetData.nestedAssetData.length).to.be.equal(expectedNestedAssetDataLength);
 | 
				
			||||||
        // validate nested asset data (outer)
 | 
					        // validate nested asset data (outer)
 | 
				
			||||||
        let nestedAssetDataIndex = 0;
 | 
					        let nestedAssetDataIndex = 0;
 | 
				
			||||||
        const decodedErc20AssetData1 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++];
 | 
					        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
				
			||||||
 | 
					        const decodedErc20AssetData1 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC20AssetData;
 | 
				
			||||||
        expect(decodedErc20AssetData1.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
 | 
					        expect(decodedErc20AssetData1.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
 | 
				
			||||||
        expect(decodedErc20AssetData1.assetProxyId).to.equal(AssetProxyId.ERC20);
 | 
					        expect(decodedErc20AssetData1.assetProxyId).to.equal(AssetProxyId.ERC20);
 | 
				
			||||||
        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
					        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
				
			||||||
@@ -158,7 +160,8 @@ describe('assetDataUtils', () => {
 | 
				
			|||||||
        expect(decodedErc1155AssetData1.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds);
 | 
					        expect(decodedErc1155AssetData1.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds);
 | 
				
			||||||
        expect(decodedErc1155AssetData1.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData);
 | 
					        expect(decodedErc1155AssetData1.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData);
 | 
				
			||||||
        // validate nested asset data (inner)
 | 
					        // validate nested asset data (inner)
 | 
				
			||||||
        const decodedErc20AssetData2 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++];
 | 
					        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
				
			||||||
 | 
					        const decodedErc20AssetData2 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC20AssetData;
 | 
				
			||||||
        expect(decodedErc20AssetData2.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
 | 
					        expect(decodedErc20AssetData2.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
 | 
				
			||||||
        expect(decodedErc20AssetData2.assetProxyId).to.equal(AssetProxyId.ERC20);
 | 
					        expect(decodedErc20AssetData2.assetProxyId).to.equal(AssetProxyId.ERC20);
 | 
				
			||||||
        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
					        // tslint:disable-next-line:no-unnecessary-type-assertion
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user