From 9e0acd1dbf77a999a5e5dcaa1767b85800c9792f Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 10 Jul 2019 18:50:34 -0700 Subject: [PATCH] copy dutch auction assetdata utils to @0x/order-utils --- packages/contract-wrappers/src/types.ts | 8 +-- packages/order-utils/CHANGELOG.json | 4 ++ packages/order-utils/src/asset_data_utils.ts | 56 +++++++++++++++++++ .../order-utils/test/asset_data_utils_test.ts | 33 +++++++++++ packages/types/src/index.ts | 6 ++ 5 files changed, 101 insertions(+), 6 deletions(-) diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index 7ae38a5f08..b0c510a157 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -9,7 +9,7 @@ import { WETH9Events, } from '@0x/abi-gen-wrappers'; import { ContractAddresses } from '@0x/contract-addresses'; -import { AssetData, OrderState, SignedOrder } from '@0x/types'; +import { OrderState, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { BlockParam, ContractEventArg, DecodedLogArgs, LogEntryEvent, LogWithDecodedArgs } from 'ethereum-types'; @@ -220,11 +220,7 @@ export enum DutchAuctionWrapperError { AssetDataMismatch = 'ASSET_DATA_MISMATCH', } -export interface DutchAuctionData { - assetData: AssetData; - beginTimeSeconds: BigNumber; - beginAmount: BigNumber; -} +export { DutchAuctionData } from '@0x/types'; export { CoordinatorServerCancellationResponse, CoordinatorServerError } from './utils/coordinator_server_types'; diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index b204c4366a..d9d846c708 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -14,6 +14,10 @@ { "note": "Add support for encoding/decoding StaticCallProxy assetData", "pr": 1863 + }, + { + "note": "Add support for encoding/decoding DutchAuction assetData", + "pr": 1943 } ] }, diff --git a/packages/order-utils/src/asset_data_utils.ts b/packages/order-utils/src/asset_data_utils.ts index 8aeb54646c..1a07944726 100644 --- a/packages/order-utils/src/asset_data_utils.ts +++ b/packages/order-utils/src/asset_data_utils.ts @@ -1,5 +1,6 @@ import { AssetProxyId, + DutchAuctionData, ERC1155AssetData, ERC1155AssetDataNoProxyId, ERC20AssetData, @@ -10,6 +11,8 @@ import { StaticCallAssetData, } from '@0x/types'; import { AbiEncoder, BigNumber } from '@0x/utils'; +import * as ethAbi from 'ethereumjs-abi'; +import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; import { constants } from './constants'; @@ -230,6 +233,59 @@ export const assetDataUtils = { staticCallData: decodedAssetData.staticCallData, }; }, + /** + * Dutch auction details are encoded with the asset data for a 0x order. This function produces a hex + * encoded assetData string, containing information both about the asset being traded and the + * dutch auction; which is usable in the makerAssetData or takerAssetData fields in a 0x order. + * @param assetData Hex encoded assetData string for the asset being auctioned. + * @param beginTimeSeconds Begin time of the dutch auction. + * @param beginAmount Starting amount being sold in the dutch auction. + * @return The hex encoded assetData string. + */ + encodeDutchAuctionAssetData(assetData: string, beginTimeSeconds: BigNumber, beginAmount: BigNumber): string { + const assetDataBuffer = ethUtil.toBuffer(assetData); + const abiEncodedAuctionData = (ethAbi as any).rawEncode( + ['uint256', 'uint256'], + [beginTimeSeconds.toString(), beginAmount.toString()], + ); + const abiEncodedAuctionDataBuffer = ethUtil.toBuffer(abiEncodedAuctionData); + const dutchAuctionDataBuffer = Buffer.concat([assetDataBuffer, abiEncodedAuctionDataBuffer]); + const dutchAuctionData = ethUtil.bufferToHex(dutchAuctionDataBuffer); + return dutchAuctionData; + }, + /** + * Dutch auction details are encoded with the asset data for a 0x order. This function decodes a hex + * encoded assetData string, containing information both about the asset being traded and the + * dutch auction. + * @param dutchAuctionData Hex encoded assetData string for the asset being auctioned. + * @return An object containing the auction asset, auction begin time and auction begin amount. + */ + decodeDutchAuctionData(dutchAuctionData: string): DutchAuctionData { + const dutchAuctionDataBuffer = ethUtil.toBuffer(dutchAuctionData); + // Decode asset data + const dutchAuctionDataLengthInBytes = 64; + const assetDataBuffer = dutchAuctionDataBuffer.slice( + 0, + dutchAuctionDataBuffer.byteLength - dutchAuctionDataLengthInBytes, + ); + const assetDataHex = ethUtil.bufferToHex(assetDataBuffer); + const assetData = assetDataUtils.decodeAssetDataOrThrow(assetDataHex); + // Decode auction details + const dutchAuctionDetailsBuffer = dutchAuctionDataBuffer.slice( + dutchAuctionDataBuffer.byteLength - dutchAuctionDataLengthInBytes, + ); + const [beginTimeSecondsAsBN, beginAmountAsBN] = ethAbi.rawDecode( + ['uint256', 'uint256'], + dutchAuctionDetailsBuffer, + ); + const beginTimeSeconds = new BigNumber(beginTimeSecondsAsBN.toString()); + const beginAmount = new BigNumber(beginAmountAsBN.toString()); + return { + assetData, + beginTimeSeconds, + beginAmount, + }; + }, /** * Decode and return the assetProxyId from the assetData * @param assetData Hex encoded assetData string to decode diff --git a/packages/order-utils/test/asset_data_utils_test.ts b/packages/order-utils/test/asset_data_utils_test.ts index ab168e9fa9..f876fed308 100644 --- a/packages/order-utils/test/asset_data_utils_test.ts +++ b/packages/order-utils/test/asset_data_utils_test.ts @@ -40,6 +40,15 @@ const KNOWN_MULTI_ASSET_ENCODING = { '0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204a7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c4800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', }; +const KNOWN_DUTCH_AUCTION_ENCODING = { + tokenAddress: '0x34d402f14d58e001d8efbe6585051bf9706aa064', + assetData: '0xf47261b000000000000000000000000034d402f14d58e001d8efbe6585051bf9706aa064', // ERC20 + beginTimeSeconds: new BigNumber(1562807905), + beginAmount: new BigNumber(5), + dutchAuctionAssetData: + '0xf47261b000000000000000000000000034d402f14d58e001d8efbe6585051bf9706aa064000000000000000000000000000000000000000000000000000000005d268e610000000000000000000000000000000000000000000000000000000000000005', +}; + describe('assetDataUtils', () => { it('should encode ERC20', () => { const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ERC20_ENCODING.address); @@ -175,4 +184,28 @@ describe('assetDataUtils', () => { expect(decodedErc1155AssetData2.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds); expect(decodedErc1155AssetData2.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData); }); + it('should encode Dutch Auction', async () => { + const encodedAssetData = assetDataUtils.encodeDutchAuctionAssetData( + KNOWN_DUTCH_AUCTION_ENCODING.assetData, + KNOWN_DUTCH_AUCTION_ENCODING.beginTimeSeconds, + KNOWN_DUTCH_AUCTION_ENCODING.beginAmount, + ); + expect(encodedAssetData).to.be.equal(KNOWN_DUTCH_AUCTION_ENCODING.dutchAuctionAssetData); + }); + it('should decode Dutch Auction', async () => { + const { assetData, beginTimeSeconds, beginAmount } = assetDataUtils.decodeDutchAuctionData( + KNOWN_DUTCH_AUCTION_ENCODING.dutchAuctionAssetData, + ); + + const { assetProxyId, tokenAddress } = assetDataUtils.decodeERC20AssetData( + KNOWN_DUTCH_AUCTION_ENCODING.assetData, + ); + + // tslint:disable:no-unnecessary-type-assertion + expect((assetData as ERC20AssetData).assetProxyId).to.be.equal(assetProxyId); + expect((assetData as ERC20AssetData).tokenAddress).to.be.equal(tokenAddress); + // tslint:enable:no-unnecessary-type-assertion + expect(beginTimeSeconds).to.deep.equal(KNOWN_DUTCH_AUCTION_ENCODING.beginTimeSeconds); + expect(beginAmount).to.deep.equal(KNOWN_DUTCH_AUCTION_ENCODING.beginAmount); + }); }); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 7bc1ff4d9a..50bc0fc338 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -216,6 +216,12 @@ export interface MultiAssetDataWithRecursiveDecoding { nestedAssetData: SingleAssetData[]; } +export interface DutchAuctionData { + assetData: AssetData; + beginTimeSeconds: BigNumber; + beginAmount: BigNumber; +} + export type AssetData = SingleAssetData | MultiAssetData | MultiAssetDataWithRecursiveDecoding; // TODO: DRY. These should be extracted from contract code.