diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index cb24e82f22..c5fd030954 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "10.3.0", + "changes": [ + { + "note": "Add ERC20 Transformer utils and export useful constants.", + "pr": 2604 + } + ] + }, { "timestamp": 1583220306, "version": "10.2.4", diff --git a/packages/order-utils/src/constants.ts b/packages/order-utils/src/constants.ts index 0c3c434995..7ef3cec026 100644 --- a/packages/order-utils/src/constants.ts +++ b/packages/order-utils/src/constants.ts @@ -157,4 +157,8 @@ export const constants = { STATIC_CALL_METHOD_ABI, IS_VALID_WALLET_SIGNATURE_MAGIC_VALUE: '0xb0671381', IS_VALID_VALIDATOR_SIGNATURE_MAGIC_VALUE: '0x42b38674', + /* + * The pseudo-token address for ETH used by the Exchange Proxy's `tranformERC20()`. + */ + ETH_TOKEN_ADDRESS: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', }; diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts index 098fb538fb..b35b070c69 100644 --- a/packages/order-utils/src/index.ts +++ b/packages/order-utils/src/index.ts @@ -60,3 +60,26 @@ export { OrdersAndRemainingTakerFillAmount, OrdersAndRemainingMakerFillAmount, } from './types'; + +export { + FillQuoteTransformerSide, + FillQuoteTransformerData, + encodeFillQuoteTransformerData, + decodeFillQuoteTransformerData, + WethTransformerData, + encodeWethTransformerData, + decodeWethTransformerData, + PayTakerTransformerData, + encodePayTakerTransformerData, + decodePayTakerTransformerData, + AffiliateFeeTransformerData, + encodeAffiliateFeeTransformerData, + decodeAffiliateFeeTransformerData, +} from './transformer_data_encoders'; + +import { constants } from './constants'; +export const NULL_ADDRESS = constants.NULL_ADDRESS; +export const NULL_BYTES = constants.NULL_BYTES; +export const ZERO_AMOUNT = constants.ZERO_AMOUNT; +export const NULL_ERC20_ASSET_DATA = constants.NULL_ERC20_ASSET_DATA; +export const ETH_TOKEN_ADDRESS = constants.ETH_TOKEN_ADDRESS; diff --git a/packages/order-utils/src/transformer_data_encoders.ts b/packages/order-utils/src/transformer_data_encoders.ts new file mode 100644 index 0000000000..00a7831f61 --- /dev/null +++ b/packages/order-utils/src/transformer_data_encoders.ts @@ -0,0 +1,187 @@ +import { Order } from '@0x/types'; +import { AbiEncoder, BigNumber } from '@0x/utils'; + +const ORDER_ABI_COMPONENTS = [ + { name: 'makerAddress', type: 'address' }, + { name: 'takerAddress', type: 'address' }, + { name: 'feeRecipientAddress', type: 'address' }, + { name: 'senderAddress', type: 'address' }, + { name: 'makerAssetAmount', type: 'uint256' }, + { name: 'takerAssetAmount', type: 'uint256' }, + { name: 'makerFee', type: 'uint256' }, + { name: 'takerFee', type: 'uint256' }, + { name: 'expirationTimeSeconds', type: 'uint256' }, + { name: 'salt', type: 'uint256' }, + { name: 'makerAssetData', type: 'bytes' }, + { name: 'takerAssetData', type: 'bytes' }, + { name: 'makerFeeAssetData', type: 'bytes' }, + { name: 'takerFeeAssetData', type: 'bytes' }, +]; + +/** + * ABI encoder for `FillQuoteTransformer.TransformData` + */ +export const fillQuoteTransformerDataEncoder = AbiEncoder.create([ + { + name: 'data', + type: 'tuple', + components: [ + { name: 'side', type: 'uint8' }, + { name: 'sellToken', type: 'address' }, + { name: 'buyToken', type: 'address' }, + { + name: 'orders', + type: 'tuple[]', + components: ORDER_ABI_COMPONENTS, + }, + { name: 'signatures', type: 'bytes[]' }, + { name: 'maxOrderFillAmounts', type: 'uint256[]' }, + { name: 'fillAmount', type: 'uint256' }, + ], + }, +]); + +/** + * Market operation for `FillQuoteTransformerData`. + */ +export enum FillQuoteTransformerSide { + Sell, + Buy, +} + +/** + * `FillQuoteTransformer.TransformData` + */ +export interface FillQuoteTransformerData { + side: FillQuoteTransformerSide; + sellToken: string; + buyToken: string; + orders: Array>; + signatures: string[]; + maxOrderFillAmounts: BigNumber[]; + fillAmount: BigNumber; +} + +/** + * ABI-encode a `FillQuoteTransformer.TransformData` type. + */ +export function encodeFillQuoteTransformerData(data: FillQuoteTransformerData): string { + return fillQuoteTransformerDataEncoder.encode([data]); +} + +/** + * ABI-decode a `FillQuoteTransformer.TransformData` type. + */ +export function decodeFillQuoteTransformerData(encoded: string): FillQuoteTransformerData { + return fillQuoteTransformerDataEncoder.decode(encoded).data; +} + +/** + * ABI encoder for `WethTransformer.TransformData` + */ +export const wethTransformerDataEncoder = AbiEncoder.create([ + { + name: 'data', + type: 'tuple', + components: [{ name: 'token', type: 'address' }, { name: 'amount', type: 'uint256' }], + }, +]); + +/** + * `WethTransformer.TransformData` + */ +export interface WethTransformerData { + token: string; + amount: BigNumber; +} + +/** + * ABI-encode a `WethTransformer.TransformData` type. + */ +export function encodeWethTransformerData(data: WethTransformerData): string { + return wethTransformerDataEncoder.encode([data]); +} + +/** + * ABI-decode a `WethTransformer.TransformData` type. + */ +export function decodeWethTransformerData(encoded: string): WethTransformerData { + return wethTransformerDataEncoder.decode(encoded).data; +} + +/** + * ABI encoder for `PayTakerTransformer.TransformData` + */ +export const payTakerTransformerDataEncoder = AbiEncoder.create([ + { + name: 'data', + type: 'tuple', + components: [{ name: 'tokens', type: 'address[]' }, { name: 'amounts', type: 'uint256[]' }], + }, +]); + +/** + * `PayTakerTransformer.TransformData` + */ +export interface PayTakerTransformerData { + tokens: string[]; + amounts: BigNumber[]; +} + +/** + * ABI-encode a `PayTakerTransformer.TransformData` type. + */ +export function encodePayTakerTransformerData(data: PayTakerTransformerData): string { + return payTakerTransformerDataEncoder.encode([data]); +} + +/** + * ABI-decode a `PayTakerTransformer.TransformData` type. + */ +export function decodePayTakerTransformerData(encoded: string): PayTakerTransformerData { + return payTakerTransformerDataEncoder.decode(encoded).data; +} + +/** + * ABI encoder for `PayTakerTransformer.TransformData` + */ +export const affiliateFeeTransformerDataEncoder = AbiEncoder.create({ + name: 'data', + type: 'tuple', + components: [ + { + name: 'fees', + type: 'tuple[]', + components: [ + { name: 'token', type: 'address' }, + { name: 'amount', type: 'uint256' }, + { name: 'recipient', type: 'address' }, + ], + }, + ], +}); + +/** + * `AffiliateFeeTransformer.TransformData` + */ +export interface AffiliateFeeTransformerData { + fees: Array<{ + token: string; + amount: BigNumber; + recipient: string; + }>; +} + +/** + * ABI-encode a `AffiliateFeeTransformer.TransformData` type. + */ +export function encodeAffiliateFeeTransformerData(data: AffiliateFeeTransformerData): string { + return affiliateFeeTransformerDataEncoder.encode(data); +} + +/** + * ABI-decode a `AffiliateFeeTransformer.TransformData` type. + */ +export function decodeAffiliateFeeTransformerData(encoded: string): AffiliateFeeTransformerData { + return affiliateFeeTransformerDataEncoder.decode(encoded).data; +}